I have a roles table
select * from roles;
id | name
----+----------
1 | admin
2 | user
3 | author
4 | guest
5 | manager
and another table user_roles
select * from user_roles;
role_id | user_id
---------+---------
3 | 1
3 | 2
3 | 3
4 | 5
3 | 6
5 | 7
5 | 8
1 | 9
1 | 11
#role.rb
class Role < ActiveRecord::Base
has_and_belongs_to_many :users, join_table: 'user_roles', class_name: user_class.to_s
end
I am trying to do some actions when a user's role is updated say, from guest
to author
#user.rb
class Use < ActiveRecord::Base
after_update :print_role_updated if: :user_roles_changed?
.
.
private
def user_roles_changed?
user_roles.any? { |role| role.changed? }
end
def print_role_updated
puts "User role changed from #{old_role} to #{new_role}"
end
end
But it is not working as expected ( .changed?
is checking whether the value in role
table is updated ?).
How do I run print_role_updated
method whenever user roles get updated to a diffrent one?
I tried Doctor's answer but role_updated?
is returning false even though the record is being updated
class Use < ActiveRecord::Base
has_many :user_roles
after_update :print_role_updated if: role_updated?
.
.
private
def role_updated?
user_roles.any? {|a| a.changed?}
end
def print_role_updated
puts "User role changed from #{old_role} to #{new_role}"
end
end
try below code in model:
class User < ActiveRecord::Base
after_update :print_role_updated if: :user_roles_changed?
.
.
private
def print_role_updated
puts "User role changed"
end
def user_roles_changed?
u = User.find(self.id)
u.role != self.role # it check existing role and role saved in db
end
end
I think the _changed?
does only work for attributes not classes. And since you have a many to many association you can't check on one object. I would try something in this direction:
if user_roles.any? {|a| a.changed?}
if a user only has a single role (sorry it is not clear from your code) then the following should work, or doesn't it ?
if user_roles.changed?
Update since you specified that a user can have many roles. There should be a few corrections you should consider:
class Use < ActiveRecord::Base
has_many :user_roles
after_update :print_role_updated if: user_roles.any? {|a| a.changed?}
.
.
private
def print_role_updated
puts "User role changed from #{old_role} to #{new_role}"
end
end
Update 2: As it turns out, changed?
is false on newly created objects, so my previous update is not working.
Try to change the changed?
to the following:
user_roles.any? { |a| a.new_record? || a.marked_for_destruction? || a.changed? }
To be honest it is a bit a guessing I do here, but can you please try it? I would love to see if that works
I found a solution. the problem is that the HABTM relationship is updated in the db as soon as the new values are set
here is my workaround for your example to implement an HABTM changed method. may not work for your exact case but knowing this you'll get the idea
class User < ActiveRecord::Base
...
def user_role_ids=(ids)
@user_roles_changed = ids != user_role_ids
super(ids)
end
def user_roles_changed?
!!@user_roles_changed
end
end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.