2
\$\begingroup\$

I've got this code in my ApplicationHelper file:

def new_button
 case controller_name
 when 'cars'
 "<li class='has-form'><a class='button' href='#{new_car_path}'>New Car</a></li>".html_safe
 when 'trucks'
 "<li class='has-form'><a class='button' href='#{new_truck_path}'>New Truck</a></li>".html_safe
 when 'mopeds'
 "<li class='has-form'><a class='button' href='#{new_moped_path}'>New Moped</a></li>".html_safe
 else
 nil
 end
end

So I can just put <%= new_button %> in the view, to display the appropriate button based on the controller_name being accessed.

I have about 10 different controllers to select from (and I'm sure that collection will grow), so the code is getting a bit lengthy.

Is there a better way to accomplish this?

asked Jun 13, 2014 at 14:57
\$\endgroup\$
0

3 Answers 3

4
\$\begingroup\$

You can use the name of your current controller to dynamically generate your buttons. Controllers names are plural by convention in Rails, so you will want to get the singular version of your controller name.

singular = controller_name.singularize # get the controller name & make it singular

You can generate path to the "new" action by using send to call a dynamic method name. If you are not using Rails resources, you can use url_for(controller: controller_name, action: "new") to accomplish the same thing.

path = send("new_#{singular}_path") # generate the URL for that item's new action

Similarly, you can dynamically generate the text for your buttons.

title = "New #{singular.titleize}" # generate the text for the link

And finally, put it all together to generate your HTML:

"<li class='has-form'><a class='button' href='#{path}'>#{title}</a></li>".html_safe # return
answered Jun 13, 2014 at 15:38
\$\endgroup\$
1
  • \$\begingroup\$ I also have an edit button with similar syntax & I found that the link could be generated with path = send("edit_#{singular}_path", item_id) if I send item_id into the method. \$\endgroup\$ Commented Jun 13, 2014 at 16:00
5
\$\begingroup\$

I haven't run this code, but maybe something along these lines:

def new_button
 content_tag(:li, class: "has-form") do
 text = "New #{controller_name.singularize.titleize}"
 path = { controller: controller_name, action: "new" }
 link_to(text, path, class: "button")
 end
end

Using content_tag and link_to is arguably cleaner, and they handle escaping automatically.

Letting the router generate the URL for you from a hash is preferable to doing string manipulation.

The text generation is perhaps inelegant, but simple. If you're using I18n elsewhere in this app I'd consider using that:

model_slug = controller_name.singularize
text = t("new_x", x: t("activerecord.models.#{model_slug}"))

But it's overkill if you're not using it for anything else.

answered Jun 14, 2014 at 17:37
\$\endgroup\$
3
\$\begingroup\$

For links, I prefer to use link_to as it is really clear to read. However, once more view code is concerned, instead of going all content_tag or typing in strings and using interpolation, which could lead to hard to find errors, and definitely hard to read code, I tend to prefer to use partials.

So your code would become something like

def new_button
 single_item = controller_name.singular
 render 'shared/new_button', title: "New #{single_item.capitalize}"
end

and in app/views/shared/_new_button.html.haml you write

%li.has-form
 = link_to title, {action: :new}, class: 'button'

Notice for the path I only need to specify the action (which is in this case always the same), since rails will automatically fill in the current controller if it is missing.

Notice how simple it would now be to make the title dependent on translations, or give it as the only parameter to new_button as it is (in the communication to the client/user) the only thing that matters (or could change easily).

answered Jun 15, 2014 at 12:50
\$\endgroup\$
1
  • \$\begingroup\$ Nice. I do agree content_tag can get a little noisy. \$\endgroup\$ Commented Jun 27, 2014 at 18:01

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.