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