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
-~----------~----~----~----~------~----~------~--~---