Lee McAlilly
Lee McAlilly

Reputation: 9316

How to pass two attributes as the text_method to a collection_select in rails

I have a collection_select in a rails form that looks like this:

<%= form.collection_select :post_id, Post.all, :id, :title, {}, { class: "mt-1 block" } %>

What I can't seem to figure out from the docs or googling, is how to pass multiple attributes from the Post to the dropdown so the user sees more than just the :title. Something like this:

<%= form.collection_select :post_id, Post.all, :id, :title + :category, {}, { class: "mt-1 block" } %>

I can create a custom method to pass to text_method like :title_with_category in the Post model like:

<%= form.collection_select :post_id, Post.all, :id, :title_with_category, {}, { class: "mt-1 block" } %>

Post.rb:

def title_with_category
  self.title + " " + self.category
end

But is this the best way to do this? If so, what is the appropriate place to define this? The model? Or should this be in a helper? If it's a helper, should it be in the application helper?

Upvotes: 0

Views: 239

Answers (2)

max
max

Reputation: 101811

You can pass a callable to collection_select for both the value_method and text_method arguments:

<%= form.collection_select :post_id,
                           Post.all,
                           :id, # value_method
                           ->(p){ "#{p.title} #{p.category}" }, # text_method
                           {},
                           { class: "mt-1 block" }
%>

A callable is any object that responds to the call method such as lamdba and proc objects.

It is called with the post for each iteration of the loop.

What is the appropriate place to define this? The model? Or should this be in a helper? If it's a helper, should it be in the application helper?

There is no clear cut answer if you choose to extract this out into a separate method. The model would be the simplest solution but you can also argue that presentational logic should be separated from buisness logic and that models already have tons of responsiblities.

I think we can all agree on that ApplicationHelper is the least suitible option unless you to just are aiming to toss your code into a junk drawer.

This code could go into Post, PostHelper, PostPresenter (if you're into the decorator pattern) or a custom form builder (which seems slightly overkill).

Upvotes: 0

TomDunning
TomDunning

Reputation: 4877

Firstly, it's safer to do this in case one of the items is ever nil:

Post.rb

def title_with_category
  "#{title} #{category}"
end

Next your selection. In the controller, return the options as an attribute:

def new
  @post_options = Post.all.collect{|post| [post.id, post.title_and_category]}
  # OR
  @post_options = Post.all.collect{|post| [post.id, "#{post.title} #{post.category}"]}
  # you can skip the model method with the second option
end

And on the form:

<%= form.select :post_id, @post_options, {}, { class: "mt-1 block" } %>

See form select.

Upvotes: 0

Related Questions