Hi,
I prefer to build the new state in an instance before committing
(after validate passes). For example, I have groups and users, and use
memberships to associate them:
class Membership < AR::Base
belongs_to :user
belongs_to :group
end
class Group < AR::Base
has_many :memberships
has_many :users, :through => :memberships
end
class User < AR::Base
has_many :memberships
has_many :groups, :through => :memberships
end
I add users to groups in the groups controller, and send an array of
user id’s to the groups controller like so: group[:users][] - then in
the controller:
def update
group = Group.find(params[:id])
group.update_attributes(params[:group])
group.save
end
And then in Group:
def users=(args)
memberships.clear
User.find(args).each do |user|
memberships.build(:user => user, :group => group)
end
end
First question: The problem is, that memberships.clear hits the DB
immediatly. I would rather clear the association in memory and then do
the delete/inserts upon commit. Is there an operation equivalent to
build which just removes a membership from the association - but only
in memory?
Second question: Using the users=(args) approach is convenient, but
somehow not quite right because the method could rely on other
properties of the group instance, eg. is_open_for_new_users? - I’m
thinking of adding a set_users method instead, and then in the
controller:
group.update_attributes(params[:group])
group.set_users(params[:users])
group.save
Any thoughts on the pros/cons of these approaches? I’m not quite
certain where to put the transaction when updating multiple model
types, but I guess that placing it in the controller, wrapping all
operations on group in the transaction is a way.
Any insight much appreciated.