Rails: add field to all forms - ruby-on-rails

Is it possible to add hidden field to all form tags?
I'm trying to do it in following way:
module ActionView::Helpers::FormTagHelper
def form_tag(url_for_options = {}, options = {}, &block)
html_options = html_options_for_form(url_for_options, options)
if block_given?
f = form_tag_in_block(html_options, &block)
else
f = form_tag_html(html_options)
end
hidden_f = ActiveSupport::SafeBuffer.new "<input name='n' type='hidden' value='v' /><\/form>"
f.gsub!(/<\/form>/, hidden_f)
f
end
end
But server shows the error:
ActionView::Template::Error (Could not concatenate to the buffer because it is not html safe.):
How should i do it?

It might be simpler to redefine the extra_tags_for_form method, which is used to add the _method, utf8, and authenticity_token hidden fields. Something like this could work:
module ActionView::Helpers::FormTagHelper
alias_method :orig_extra_tags_for_form, :extra_tags_for_form
def extra_tags_for_form(html_options)
orig_tags = orig_extra_tags_for_form(html_options)
orig_tags << "<input name='n' type='hidden' value='v' /><\/form>".html_safe
end
end
Since this advice involves redefining a private method, you will need to be sure to test it carefully any time you upgrade Rails.

Try with
module ActionView::Helpers::FormTagHelper
def form_tag(url_for_options = {}, options = {}, &block)
html_options = html_options_for_form(url_for_options, options)
if block_given?
f = form_tag_in_block(html_options, &block)
else
f = form_tag_html(html_options)
end
hidden_f = ActiveSupport::SafeBuffer.new "<input name='n' type='hidden' value='v' /><\/form>"
f.gsub!(/<\/form>/, hidden_f)
f.html_safe
end
end
gsub! taints your string with HTML unsafeness.

Related

In Rails ERB view, how can I prevent underscore from being converted to hyphen?

Having the following code in an ERB view:
<%= content_tag(:div, id: 'stat', data: {_var_: '_foo_'}) %>
generates the following HTML:
<div id="stat" data--var-="_foo_">
</div>
My intention is to obtain
<div id="stat" data-_var_="_foo_">
</div>
i.e. I do not want
data--var-
but instead
data-_var_
How can I achieve this, please ?
As pointed in the ActionView::Helpers::TagHelper docs:
To play nicely with JavaScript conventions sub-attributes are
dasherized. For example, a key user_id would render as data-user-id
and thus accessed as dataset.userId.
To illustrate, you can check in the Rails source code (tag_helper.rb) prefix_tag_option invoking key.to_s.dasherize:
def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)
#...#
content_tag_string(name, content_or_options_with_block, options, escape)
#...#
end
def content_tag_string(name, content, options, escape = true)
tag_options = tag_options(options, escape) if options
#...#
end
def tag_options(options, escape = true)
# ...
# TAG_PREFIXES = ['aria', 'data', :aria, :data].to_set
# invoke prefix_tag_option only if it's a data- sub-attributes
if TAG_PREFIXES.include?(key) && value.is_a?(Hash)
#...#
output << prefix_tag_option(key, k, v, escape)
end
#...#
end
def prefix_tag_option(prefix, key, value, escape)
key = "#{prefix}-#{key.to_s.dasherize}"
#...#
end
If you don't want to dasherize your keys, a possible "workaround" is to set the data-attribute directly in the options hash, like this:
<%= content_tag(:div, "test", { id: 'stat', 'data-_var_': '_foo_' }) %>
This way, Rails will render:
<div id="stat" data-_var_="_foo_">test</div>

Rails - Pass options into a helper method that accepts a block?

I have a helper that creates mailer template rows (html). I want to be able to pass in styles to the row (optionally), like a background color.
module MailHelper
def module_row(&block)
h << "<table border='0' cellpadding='0' cellspacing='0' width='100%'>"
# more table html here
h << capture(&block)
# more table html here
h << "</table>"
raw h
end
end
I want to be able to optionally pass in a background color, but I can't seem to figure out how to do that while passing in the '&block'. Is this possible in Ruby?
You sure can!
module MailHelper
def module_row(options={}, &block)
...
if options[:foo]
do_foo_stuff
end
end
end
<% module_row(foo: true) do |x| %>
...
<% end %>
Common practice is to define defaults like this:
def module_row(options={}, &block)
opts = {
foo: true,
background_color: 'black'
}.merge!(options)
if opts[:foo]
do_foo_stuff
end
end
You can pass options as a Hash well, like:
module MailHelper
def module_row(**opts, &block)
bgcolor = opts[:bgcolor] || '#FFFFFF'
...
h << "<table border='0' cellpadding='0' cellspacing='0' width='100%'>"
# more table html here
h << capture(&block)
# more table html here
h << "</table>"
raw h
end
end
Then you can call:
module_row(bgcolor: '#AAAAAA', &my_block)
or:
module_row(bgcolor: '#AAAAAA') { block content }

Send helper additional class

In a rails 4 app, I'm trying to pass a default option to the text_field helper, but seem to be stuck on how to implement this.
So far, I have in my view:
<%= new_text_field :name, class: "", placeholder: "" %>
and in my application_helper.rb
def new_text_field(object_name, method, options = {})
text_field(object_name, method, options = {}) # Trying to pass in a default class here, for example ".bigger"
end
Try this:
def new_text_field(object_name, method = nil, options = {})
options[:class] ||= 'bigger' # this will set bigger as default value if "class" option isn't passed
text_field(object_name, method, options = {})
end
Something like this should work:
def new_text_field_tag(name, value=nil, options)
your_class = "bigger"
if options.has_key?(:class)
options[:class] += " #{your_class}"
else
options[:class] = your_class
end
text_field_tag(name, value, options)
end

Rails 3 - Custom link_to helper (with default class and ability to add classes)

I'm trying to hook up a custom helper that has a default class 'pjax' but also retains an ability to add classes where need be.
Example:
link_to_pjax('pagename', page_path, :class => 'current')
So the helper would add the 'pjax' by default, and also the class 'current', or whatever is passed in.
def link_to_pjax(name, path, options = {:class => 'pjax'})
link_to(name, path, options)
end
The syntax is freaking me out. Any advice would be much appreciated.
def link_to_pjax(name, path, options)
options[:class] += ' pjax'
link_to(name, path, options)
end
edit
After test, it's much less elegant:
def link_to_pjax(name, path, options = {})
options[:class] ? options[:class] += ' pjax' : options[:class] = 'pjax'
link_to(name, path, options)
end
My first solution works but only if you have still specified a class.
The latest works in all cases:
link_to_pjax 'click me', my_super_path, class: 'ahah', id: 'hello'
link_to_pjax 'click me', my_super_path
etc
My bad...
def link_to_pjax(name, path, options={})
default_options = { :class => "pjax" }
link_to(name, path, options.merge(default_options))
end
I improved Delba answer to handle block version of link_to:
def link_to_pjax(*args, &block)
if block_given?
options = args.first || {}
html_options = args.second
link_to_pjax(capture(&block), options, html_options)
else
name = args[0]
options = args[1] || {}
html_options = args[2] || {}
html_options[:class] ? html_options[:class] += ' pjax' : html_options[:class] = 'pjax'
link_to(name, options, html_options)
end
end

How do I make link_to open external URLs in a new window?

I need to convert a rails 2.3 site so that all external URLs open in a new window. I could go though every call to link_to and add :target => '_blank', but I'd like to do it in one step for all links, present and future. Is there a way I can monkey patch link_to to get the desired behaviour?
You should not have to change your server-side code for this view problem.
You should use Unobscursive javascript.
This example will only make external links showing up in a new window :
// jQuery
//
$(document).ready(function() {
$("a").click(function() {
link_host = this.href.split("/")[2];
document_host = document.location.href.split("/")[2];
if (link_host != document_host) {
window.open(this.href);
return false;
}
});
});
In the end I went with this, in an initialiser:
module ExternalLinksInNewTabs
def new_tab_link_to *args, &block
if block_given?
options = args.first || {}
html_options = args[1] || {}
if options.is_a? String
if ExternalLinksInNewTabs.is_external_link? #controller.request.host, options
html_options[:target] = '_BLANK'
end
end
same_tab_link_to options, html_options, &block
else
name = args.first
options = args[1] || {}
html_options = args[2] || {}
if options.is_a? String
if ExternalLinksInNewTabs.is_external_link? #controller.request.host, options
html_options[:target] = '_BLANK'
end
end
same_tab_link_to name, options, html_options
end
end
def self.is_external_link? host, url
host.sub! /^www\./, ''
url =~ /^http/i && url !~ /^http:\/\/(www\.)?#{host}/i
end
end
module ActionView
module Helpers
module UrlHelper
include ExternalLinksInNewTabs
alias_method :same_tab_link_to, :link_to
alias_method :link_to, :new_tab_link_to
end
end
end
You just add an helper to add this options in your link_to
If you want add it on each link_to to can add on ApplicationHelper
def link_to(*args, &block)
if block_given?
args = [(args.first || {}), (args.second || {}).merge(:target => '_blank')]
else
args = [(args.first || {}), (args.second || {}), (args.third || {}).merge(:target => '_blank')]
end
super(args, block)
end
Or you can create your own link_to helper
def link_to_blank(*args, &block)
if block_given?
args = [(args.first || {}), (args.second || {}).merge(:target => '_blank')]
else
args = [(args.first || {}), (args.second || {}), (args.third || {}).merge(:target => '_blank')]
end
link_to(args, block)
end
In rails 3.2+, it has been added as an option, just add
= link_to 'facebook', 'http://www.facebook.com/fb-page', target: '_blank'
and it'll open the link in a new tab.

Resources