Bernard Dubuisson
2006-Apr-01 19:21 UTC
[Rails] acts_as_list with scope : position update problem?
Hello, I''ve tried to set up a class with acts_as_list with a scope argument that restricts a list to records with the same foreign key. For example : database : CREATE TABLE `families` ( `id` int(11) NOT NULL auto_increment, `name` varchar(255) NOT NULL default '''', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ; INSERT INTO `families` VALUES (1, ''Smith''); INSERT INTO `families` VALUES (2, ''Jones''); CREATE TABLE `people` ( `id` int(11) NOT NULL auto_increment, `name` varchar(255) NOT NULL default '''', `family_id` int(11) default NULL, `position` int(5) NOT NULL default ''0'', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ; INSERT INTO `people` VALUES (1, ''Robert'', 1, 1); INSERT INTO `people` VALUES (2, ''Brian'', 1, 2); INSERT INTO `people` VALUES (3, ''John-Paul'', 2, 1); INSERT INTO `people` VALUES (4, ''Grace'', 2, 2); class Family < ActiveRecord::Base has_many :people end class Person < ActiveRecord::Base belongs_to :family, :order => ''position'' acts_as_list :scope => ''family_id'' validates_uniqueness_of :position, :scope => ''family_id'' end Now, all this works fine, I can execute commands like person.move_higher, person.move_to_bottom, etc. So the class behaves as expected with acts_as_list, updating the position column all by itself :>> @person = Person.find_by_id(2)=> #<Person:0x239cd64 @attributes={"family_id"=>"1", "name"=>"Brian", "id"=>"2", "position"=>"2"}>>> @person.move_higher=> true>> @person.position=> 1 Except for one thing : when I change a Person''s scope (thus changing the value for family_id), nothing gets updated except the scope value. The position column doesn''t change :>> @person.family_id = 2=> 2>> @person=> #<Person:0x239cd64 @attributes={"family_id"=>2, "name"=>"Brian", "id"=>"2", "position"=>1}> I would expect the "acts_as_list with scope" behavior to ; a) update all the positions of the objects in the original scope to mend the gap left by the departure of the updated record moved to another scope, b) the moved object to be added to the bottom of the list corresponding to its new family_id scope. This appears not to be the case. The validation method raises an error if the position of the object to update already exists in the new scope (though not in console). This is what I have tried, although not working. I somehow can''t access params() from the callback method, and I can''t figure out what''s wrong. class Person < ActiveRecord::Base belongs_to :family, :order => ''position'' acts_as_list :scope => ''family_id'' validates_uniqueness_of :position, :scope => ''family_id'' before_validation_on_update :reorder_positions private def reorder_positions @updated_family_id = params[:person][:family_id] unless @updated_family_id == self.family_id self.move_to_bottom # reorder original list params[:person][:family_id] = Family.find_by_id(@updated_family_id).people.length + 1 end end end When I update a Person by changing its family_id, I get this error message : "undefined local variable or method `params'' for #<Person:0x22e5060>" Can someone help me figure it all out? Am I making this more complicated than it really is? Thanks in advance ! Bernard. -- Posted via http://www.ruby-forum.com/.
Bernard Dubuisson
2006-Apr-02 09:46 UTC
[Rails] Re: acts_as_list with scope : position update problem?
Actually, I found a workaround by myself, including the position reordering directly inside the people controller update method like so : def update @person = Person.find(params[:id]) unless params[:person][:family_id] == @person.family_id @person.move_to_bottom params[:person][:position] = Family.find(params[:person][:family_id]).people.length + 1 end if @person.update_attributes(params[:person]) flash[:notice] = ''Person was successfully updated.'' redirect_to :action => ''list'' else render :action => ''edit'' end end It works fine... but I''m concerned about breaking the MVC model, since such a kind of rectification should belong to the model, not the controller, shouldn''t it? Although, I still can''t access the params hash from a callback method in the model. Still that error : "undefined local variable or method `params'' for #<Person:0x22e5060>" Bernard. -- Posted via http://www.ruby-forum.com/.
Thomas Balthazar
2006-Jul-21 21:54 UTC
[Rails] Re: acts_as_list with scope : position update problem?
Hello Bernard, I faced the same problem. I found this solution to solve the problem in my Model : 1/ in my controller, I update the Person object with : @person.update_attributes(params[:person]) 2/ so in my Person model, I have overwritten the update_attributes method : def update_attributes(attributes) # reorder the positions if the category has changed reorder_positions(attributes[:category_id]) unless attributes[:category_id].to_s==self.category_id.to_s super(attributes) end 3/ the "reorder_positions" method in my Person model : private def reorder_positions(new_category_id) # reorder source list self.move_to_bottom # find the position in the destination list new_position = Category.find(new_category_id, :include => "contents").contents.length + 1 end Hope this helps. Thomas Balthazar. On 4/2/06, Bernard Dubuisson <bernard@dub.be> wrote:> Actually, I found a workaround by myself, including the position > reordering directly inside the people controller update method like so : > > def update > @person = Person.find(params[:id]) > unless params[:person][:family_id] == @person.family_id > @person.move_to_bottom > params[:person][:position] > Family.find(params[:person][:family_id]).people.length + 1 > end > if @person.update_attributes(params[:person]) > flash[:notice] = ''Person was successfully updated.'' > redirect_to :action => ''list'' > else > render :action => ''edit'' > end > end > > It works fine... but I''m concerned about breaking the MVC model, since > such a kind of rectification should belong to the model, not the > controller, shouldn''t it? Although, I still can''t access the params hash > from a callback method in the model. Still that error : > > "undefined local variable or method `params'' for #<Person:0x22e5060>" > > Bernard. > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
Bernard Dubuisson
2006-Sep-25 21:25 UTC
Re: Re: acts_as_list with scope : position update problem?
Thanks Thomas, That was indeed a much cleaner solution. For the record though it didn''t work for me until I added a line to the rewritten update_attributes method in the model, like so : def update_attributes(attributes) # reorder the positions if the category has changed unless attributes[:category_id].to_s==self.category_id.to_s reorder_positions(attributes[:category_id]) #this is needed to get rid of the old params[:position] attributes.delete("position") end super(attributes) end Otherwise, the old position stuck in the params hash was still in the way upon updating. Cheers Bernard. Thomas Balthazar wrote:> Hello Bernard, > > I faced the same problem. > I found this solution to solve the problem in my Model : > > 1/ in my controller, I update the Person object with : > @person.update_attributes(params[:person]) > > 2/ so in my Person model, I have overwritten the update_attributes > method : > def update_attributes(attributes) > # reorder the positions if the category has changed > reorder_positions(attributes[:category_id]) unless > attributes[:category_id].to_s==self.category_id.to_s > super(attributes) > end > > 3/ the "reorder_positions" method in my Person model : > private > def reorder_positions(new_category_id) > # reorder source list > self.move_to_bottom > > # find the position in the destination list > new_position = Category.find(new_category_id, :include => > "contents").contents.length + 1 > end > > Hope this helps. > Thomas Balthazar.-- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk -~----------~----~----~----~------~----~------~--~---