Pick a specific item from a list with objects

Hi,

When I do this: debug user.declarations_payers

I get this: - !ruby/object:DeclarationsPayer   attributes:     declaration_id: "1"     id: "1"     additional_persons: "3"     user_id: "1" - !ruby/object:DeclarationsPayer   attributes:     declaration_id: "2"     id: "2"     additional_persons: "2"     user_id: "1"

Is there a way I can pick the one with declaration_id: "1" without looping throught the list? I tried this: DeclarationsPayer.find(:first, :conditions => ['user_id = ? AND declaration_id = ?', user.id, @declaration.id])

But the disadvantage is that it generates a query. And it fails if find() does not return an object.

Thanks!

user.declarations_payers.find_by_declaration_id 1

Yes it'll generate a query, but so would just pulling all the declarations_payers.

You can also do user.declarations_payers.select {|p| p.declaration_id == 1} but that loops through the list. Anyway I'd prefer the first method by far.

Pat

Thanks! And is there a way to ignore errors while doing this: DeclarationsPayer.find(:first, :conditions => ['user_id = ? AND declaration_id = ?', user.id, @declaration.id])

I think a try/catch or if block would do the trick. But is there any other way?

No errors are thrown if you do it that way. If there's no record that matches those criteria, the find method will return nil.

Pat

Ah, sorry. I saw it was incomplete.... I did something like this: <%= DeclarationsPayer.find(:first, :conditions => ['user_id = ? AND declaration_id = ?', user.id, @declaration.id]).additional_persons %> And then it throws a message because (of course) the method does not exist.

Anyone? Maybe a supershort if-statement? Like: <%= 1 = 1 ? 'OK' : 'Not OK' %>

Anyone? Maybe a supershort if-statement? Like: <%= 1 = 1 ? 'OK' : 'Not OK' %>

First off, you shouldn't be putting something like that in an rhtml document, your controller should do all your find()'s for you and then pass the resultsets in as local variables to your views.

Views should be just that - they shouldn't know that models, etc exist at all... they just get handed some data to work into a template.

That said, try this in your controller:

def declarations   if person = DeclarationsPayer.find(...)     collection = person.additional_persons   else     collection =   end

  render :locals => { :collection => collection } end

Then, you can just have your view (in this case declarations.rhtml) iterate over the collection, which, if the person was found, will be populated with additional_persons... if not, it will be empty.

  Cheers,     Tyler

Thanks! But what does render :locals => {:collection => collection} do? What are locals? And why "collection"? Is that something from Ruby? Or did you make that up? And why twice the "collection"? Should I then create a partial that's called _collection or something like that?

I now created a method in my user model like:

  def getAdditionalpersonsForDeclaration(declaration_id)     declarations_payer = self.declarations_payers.find_by_declaration_id(declaration_id)

    if !declarations_payer.nil?       return declarations_payer.additional_persons     end   end

Is that all right too?

Thanks in advance.

Thanks! But what does render :locals => {:collection => collection} do?

  Locals are passed into your view as local variables. So if you say

  :locals => { :foo => "bar" },

  then the variable "foo" in your view will contain the string bar, and you can use it like so:

  <%=foo%>

What are locals? And why "collection"? Is that something from Ruby? Or did you make that up? And why twice the "collection"?

  "Why twice" should be obvious from my above comment. I picked "collection" because that's what you're returning, a collection of "additional people".

Should I then create a partial that's called _collection or something like that?

  If you want, then in the view that's actually displaying it, you could do something like:

  <%=render :partial => 'additional_person', :collection => collection%>

  ... which would cause that partial to be rendered once for each additional person in that collection.

I now created a method in my user model like:

  def getAdditionalpersonsForDeclaration(declaration_id)     declarations_payer = self.declarations_payers.find_by_declaration_id(declaration_id)

    if !declarations_payer.nil?       return declarations_payer.additional_persons     end   end

Is that all right too?

  I guess it's fine, but since it's all about declarations and isn't thinking about users at all, does it really belong in the user model?

  I could see something like this being in the user model if you wanted to assert that the declaration actually BELONGED to the user, eg;

  def declaration_additional_persons(declaration_id)     payer = DeclarationsPayers.find_by_declaration_id(declaration_id)          if payer       unless payer.user_id == self.id         raise RuntimeError.new, "Declaration payer does not belong to this user!"       end       return payer.additional_persons     else       return nil # or if you dont want to catch nil in your controller/view     end   end

  Cheers,     Tyler

OK. Thanks. A lot clearer. But why: render :locals => { :collection => collection } instead of: @collection = person.additional_persons

And I have a block of code that has to be in update and create. How would you do that?

It's this code:

    @declarations_payers = params[:declarations_payers]     @additional_persons = params[:additional_persons]

    #First remove all declarations     @declaration.declarations_payers.destroy_all

    #Daarna één voor één weer toevoegen     if @declarations_payers       @declarations_payers.each_value { |user_id|

        #Add new object         @declarations_payer = DeclarationsPayer.new

        #Set user_id variable (from post)         @declarations_payer.user_id = user_id

        #Add aditional persons (from post)         @declarations_payer.additional_persons = @additional_persons[user_id]

        #Add the object to the declaration object         @declaration.declarations_payers << @declarations_payer       }     end

Thank you very much for all your help!

OK. Thanks. A lot clearer. But why: render :locals => { :collection => collection } instead of: @collection = person.additional_persons

   It's a matter of style, really... the only technical difference is, doing "@collection" sets an instance variable on your controller, whereas passing it via :locals makes it a local variable in the view (nothing to do with the controller).

And I have a block of code that has to be in update and create. How would you do that?

  I'd override the "save" method with:

  def presave      [your code...]   end

  def save       presave       super   end

Thank you very much for all your help!

   No problem! :slight_smile:

   Cheers,      Tyler