Modifying Rails helpers to add HTML classes - ruby-on-rails

I'm starting to use the jQuery UI CSS Framework for an app, which means I have to start adding classes to everything. So, for example, I want to make all buttons jQuery-themed, which means adding a class to all buttons.
I imagine there's some way in Rails to modify the helpers so I don't have to manually add a :class => 'blah' to every button, but I can't work it out. Is this possible, or does anybody have any better ideas?

You just need override the helper method with this class add. In your application_helper.rb
def button_to(name, options = {}, html_options = {})
super(name, options, html_options.merge(:class => 'blah'))
end

Why not use jquery, somthing like:
$('button').attr('class', 'blah');

Related

Can a `<button type="submit">` be used in place of a `f.submit` in a Rails `form_for` form?

I'm looking to standardize all the buttons and button-styled elements in our Rails app with a button component. This means rendering a styled <button> element with type "button" or type "submit". I'm making use of the view_component gem provided by github!
I am hoping to be able to replace all Rails form helper-y elements such as button_tag, submit_tag and f.submit with a button element. I'm pretty new to Rails, and I am not sure if there are things happening under the hood I'm not taking into account. Looking at the Rails documentation, it doesn't seem like there anything special with the f.submit form helper element.
Am I missing something? Are there consequences to replacing rails form helper submits with a button[type='submit']?
It would be long way to change stuff, so Better to use css and adjust css to get your requirements.
Just add following in you code to create your own my_submit_button
### app/helpers/application_helper.rb ###
module ApplicationHelper
def my_submit
# decide what the submit text should be
text = if #record.new_record?
"Create #{#record.class}"
else
"Update #{#record.class}"
end
# build and return the tag string
my_submit_tag(text)
end
end
further you can read here
The form_for helper

To extend rails' `link_to`, should I use `alias_method_chain` or mixins + inheritance?

I'm creating an app using twitter bootstrap. I'm using Font Awesome to add icons to various places, very often links. So far I've been using a global helper. Here's the simplified version:
# app/helpers/link_to_with_icon.rb
def link_to_with_icon(text, path, options={})
options = options.clone
icon = options.delete(:icon)
text = "<i class='#{icon}'></i> #{text}" if icon.present?
link_to(text, path, options)
end
This worked, but I had to remember changing link_to to link_to_with_icon every time I needed to add an icon to a new link (the app is new, so that's kindof in constant flux). So I decided to stop using link_to completely, and replaced it with link_to_with_icon (since it is compatible).
But then I realized that since I'm not using link_to any more, I might as well modify link_to in the first place. Surely I could add some monkeypatching on the lib folder to make it understand the :icon option.
# lib/extensions/url_helper_extensions.rb
module ActionView
module Helpers
module UrlHelper
# do some magic here
end
end
end
I've done things similar to this before, a couple years ago. In that time alias_method_chain helper was the right tool for the job. In rails 3.x it seems to be deprecated in favor of modules and inheritance.
But if I'm understanding the examples in that page correctly, I would need the link_to method to be provided by some kind of Base module - otherwise you can't add a "Pre-Extension" to it.
Hence my question: Can I extend link_to using modules? Or must I use alias_method_chain?
In particular, a working implementation of the :icon option would be greatly appreciated.
I'd simply do:
# app/helpers/my_helper.rb
module MyHelper
def link_to(text, path, options={})
options = options.clone
icon = options.delete(:icon)
text = "<i class='#{icon}'></i> #{text}" if icon.present?
super(text, path, options)
end
end
But watch out if ever you use link_to with block.
I would either add this in a separate helper, or add it into ApplicationHelper
def link_to(text, path, options = {}, &block)
icon = options.delete(:icon)
text = content_tag(:i, text, :class => icon) if icon
super
end
And you don't want to clone the options Hash because you don't want the icon option to be sent to the original link_to method.

Rails: Proper way to add functionality to rails methods

I'm just starting to tinker with extending the rails framework, and as an experiment, I thought I'd add some extra info inside the form_for helper. Specifically, when form_for is called, I'd like to generate an extra h1 tag such as:
# regular form_for <form> opening tag
<h1>Woohoo! It's added!</h1>
# tags fed into form_for via &proc
# form_for close <form> tag
At the moment I've added a /lib file that opens up ActiveRecord::FormHelper and overrides "form for". Needless to say writing out the whole form_for method with just the one added line added is dog ugly...but I can't call super() because, well, instead of inheriting from the method I'd like to super(), I've just overwritten it in /lib.
So, assuming I stubbornly want the functionality to be called via the same form_for tag (instead of, for example extended_form_for), what's the standard way for calling back to the original form_for method I'm overwriting? alias_method_chain? Thought I'd ask before I cement in some potentially lousy practices. If any hardened veterans could give an example I'd be appreciative.
Cheers
You could override form_for in your ApplicationHelper:
module ApplicationHelper
def form_for(*)
content_tag(:h1, "Woohoo! It's added!") + super
end
end
alias_method_chain is by far the simplest way to overwrite the method while still being able to call the original method. So in your lib file you'll want something like this:
def form_for_with_header(...)
form_for_without_header(...)
content_tag(:h1, "Header tag here")
# etc...
end

Where do I put this helper function, in the model or post_helper or?

All my controllers inherit from applicatin_controller.rb, and I added:
helper :all
I want to use this function in my view to make url's like:
/post/some-title
instead of using the ID int he url
def post_path_for(post)
post_path(:id => post.title_parameterize)
end
This is rails 3.
Can't you use "to_param" in your model to change that without having to write a helper?
http://apidock.com/rails/ActiveRecord/Base/to_param
It depends on how you want to use it.
If it's in helper, you could call <%= post_path_for post %> in your view.
If it's in model, with small change you could call it like this: <%= post.path %>
Although second way is shorter, I usually put such functions in helpers, for the sake of separation of logic and presentation.
I agree with Nikita. It sounds like a helper to me. I use helpers for anything that is meant for display. It sounds like you want this available to all views. If that is the case, I would place it in helpers/application_helper.rb
+1 for Robin's to_param method. By using to_param, you could use the built-in url helpers (like link_to, url_for, ...natively)
For the other point, you mentioned you put it in controller and wanted to use it in view. You need the following line:
helper_method :post_path_for

How to mixin and call link_to from controller in Rails?

This seems like a noob question, but the simple answer is eluding me. I need to call link_to in an ActionController method to spit out an HTML link. ActionView::Helpers::UrlHelper.link_to calls url_for, but this calls the AV module's version instead of the controller's. I managed to coerce this into doing what I intended by putting
#FIXME there must be a better way to mixin link_to
alias_method :self_url_for, :url_for
include ActionView::Helpers::UrlHelper
alias_method :url_for, :self_url_for
in the controller. But, I'm still not sure why it works exactly. Could someone please explain the method scope and hiding that's happening here? What's a better way to mix in link_to (or generally, to include only some methods from a module) so I can call it in the controller (generating a flash string with a link is the use case.)
Please, no lectures about MVC--if anything, link_to should be in a module separate from url_for. Judging from the amount of noise on this, lots of people run into this seemingly trivial snag and end up wasting an hour doing it the "Rails way" when really what is wanted is a one minute hack to make my app work now. Is there a "Rails way" to do this with helpers perhaps? Or a better ruby way?
Compatible with Rails 3,4 and 5:
view_context.link_to
This doesn't really answer your question but there is an easier way
For Rails 5, use the helpers proxy
helpers.link_to '...', '...'
For Rails 3 and 4, since you are using the helper from a controller you can use the view_context
# in the controller code
view_context.link_to '...', '...'
# instead of using your mixin code
link_to '...', '...'
For Rails 2, since you are using the helper from a controller you can actually access the #template member variable of the controller, the #template is the view and already has the UrlHelper mixed in
# in the controller code
#template.link_to '...', '...'
# instead of using your mixin code
link_to '...', '...'
if you need to use the urlhelper from code other than the controller, your solution is probably the way to go
I still had problems using my own helper methods that use built-in helper methods in a controller with ActionController.helper.my_method.
Obviously using render_to_string for each flash would work, but I don't want to create so many small partials for each flash.
My solution was to create a little helper for controllers to execute code in a partial.
The helper method in the controller:
def h(&block)
render_to_string(:partial => 'helper', :locals => {:block => block})
end
The HAML partial (helper.html.haml):
= instance_eval &block
Same would work in ERB (helper.html.erb):
<%= instance_eval &block %>
Use it like this in your controller to call the my_custom_helper_function that's defined in a helper:
redirect_to url, :notice => h{my_custom_helper_function}
You can do it like this:
ActionController.helpers.link_to("Click Me!", awesome_path)
But really, a better place to generate that link might be in a helper module where UrlHelper and other view-related helpers are already included.
[update]
This approach is outdated and no longer works.

Resources