user2419316
user2419316

Reputation: 331

Rails how do I locate and update a column in another model?

I'm trying to locate all subscriptions that have the expiry_date and subscription marked to expired... those each one would pluck its user id and then update that user's role to cancelled. I've come up with the following, but its not truly working.

sub = Subscription.where(:subscription_plan => 'cancelled', :expiry_date => Time.now.beginning_of_day).each do |subscription|
    user = subscription.pluck(:user_id)
    user.role = 'cancelled'
    user.save!
end

If I just do the following for testing, it works but only for one user

Subscription.where(:subscription_plan => 'cancelled', :expiry_date => Time.now.beginning_of_day).pluck(:user_id)

Upvotes: 0

Views: 64

Answers (3)

Travis Pessetto
Travis Pessetto

Reputation: 3298

According to this Rails documentation. I think you may be using pluck in the wrong way, as it states:

Use pluck as a shortcut to select one or more attributes without loading a bunch of records just to grab the attributes you want.

Also on this Rails page it states:

Unlike select, pluck directly converts a database result into a Ruby Array, without constructing ActiveRecord objects. This can mean better performance for a large or often-running query. However, any model method overrides will not be available.

It is important to note where it says, "without constructing ActiveRecord objects." You are using pluck as if it were returning an ActiveRecord object, which again, isn't what it does.

Let's go through your code to show what I mean:

sub = Subscription.where(:subscription_plan => 'cancelled', :expiry_date => Time.now.beginning_of_day).each do |subscription|
    user = subscription.pluck(:user_id) #user now equals an array of integers (ids not objects)
    user.role = 'cancelled'  #array does not have a "role method"
    user.save!  #again, this is an array, not an active record object
end

Assuming that you have the proper associations set up you could do something like:

Subscription.where(:subscription_plan => 'cancelled', :expiry_date => Time.now.beginning_of_day).each do |subscription|
    subscription.user.role = 'cancelled'
    subscription.user.save! 
end

Of course, I am making some assumtions about your associations. I am assuming that subscription belongs_to user and that user either has_one or has_many subscriptions.

Upvotes: 0

Jeremiah
Jeremiah

Reputation: 833

You should set up the appropriate ActiveRecord associations to make this sort of thing trivial.

Also, look into scopes. They are quite useful.

With the proper associations and scopes, you should be able to do something like this:

users = Subscription.expired.users

users.each do |user|
  user.role = 'cancelled'
  user.save!
end

Or use the clever update_all method that Rahul Singh suggested with associations and scopes.

Upvotes: 2

Rahul Singh
Rahul Singh

Reputation: 3427

pluck(:user_id) only returns array of user ids , you can do it as

user_ids = Subscription.where(:subscription_plan => 'cancelled', :expiry_date => Time.now.beginning_of_day).pluck(:user_id)

User.where("id IN (?)",user_ids).update_all(role:"canceled")

Upvotes: 2

Related Questions