JimboTwice JimboTwice - 7 months ago 10
SQL Question

How to remove DB record from eager-loaded table array using ActiveRecord and Ruby

We have a users table with accounts and patients tables, that both belong_to :user. We eager load the accounts and patients table for a given user record like this:

user = User.includes([:accounts, :patients]).find_by(email: "testemail@here.com")


...and this works fine. If we want to add a record to a user's accounts table in a manner that both A) commits the new record to the database and B) automatically adds the new record to the eager-loaded array, we execute this:

user.accounts.create(:name => "test name", :customer => "test customer")


...and this also works fine. However, how do we destroy a specific record in such a way that both A) removes the record from the database and B) automatically removes the record from the eager-loaded array? We have tried simply using something akin to:

account1 = user.accounts.first
account1.destroy


...and this does delete the record from the database, but does not automatically remove it from the eager-loaded array. How do we destroy a record in such a manner that it both removes it from the database and removes it from the eager-loaded array?

Answer

You want:

account1 = user.accounts.first
user.accounts.destroy(account1)

It actually doesn't matter for your question, or the answer, that you eager-loaded the association. What matters is that the user.accounts association has already been loaded (whether by eager-loading or ordinary on-demand loading), and you want to destroy one of the objects such that, like you say, it both removes it from the database and removes it from the already-loaded in-memory association.

You do that by using the destroy method that any has-many association has.

This destroy method on any has-many association, and others available on any has-many association, are briefly summarized in the Rails Guide, and in a little bit more details in the API docs for the has_many association.

user.accounts.destroy is sort of the inverse of user.accounts.create you already knew about.

Another useful one is << method on a has-many association, which is like create but with an already existing Account object instead of a hash of attributes like create.

account = Account.new(:name => "test name", :customer => "test customer") 
user.accounts << account

...which both creates the new account object and adds it to the in-memory user.accounts association.

There are a handful of other useful methods that are available on any has-many association, as well as slightly different sets of useful methods that go along with belongs_to or has_one, etc. Worth reviewing the docs, linked above, to see what's available. (I forget about some of them sometimes, or remember they exist but forget the method signature and have to look it up).