I want to post some data as an html attribute. Suppose there is a rails variable
#fields = [{:name => "id", :type => :integer}]
I want to post in the page for use with jquery's .data(). So in the .html.erb I have
<%= form_tag( {:action => 'whatever'}, {... , :"data-fields" => h(#fields.to_json)}) %>
But while rendering, the quotations in string [{"name":"id","type":"integer"}] mess up the other attributes because Rails form_tag uses double quotes to enclose the whole json string in double quotes. How do I post json with strings as an attribute from Rails?
Have you tried the following?
<%= form_tag { :action => "whatever" }, { :data => { :fields => h(#fields.to_json) } } %>
Have you tried escape_javascript ? Although it has known downsides, it is not exactly for escaping JSON, and I am not sure escaped quotes will work in HTML attributes.
There is an episode on railscasts addressing your situation using a serializer. The point is that the serializer replaces double quotes with $quot; The serialuzer also gives you the ability to select which attributes to serialize and include associations.
After some trial and error this is what works.
Server side:
<% #fields = [{:name => "id", :type => :integer}] %>
<%= form_tag( '/posts/new', {id:'example',:data => { :fields=>#fields}}) %>
Generated HTML:
<form accept-charset="UTF-8" action="/posts/new" data-fields="[{"name":"id","type":"integer"}]" id="example" method="post">
Javascript wiht JQuery's data method
fields = $('#example').attr('data-fields')
I'm using rails 2.3.8 and jquery-rails 2.2.1
Here is how I side-stepped the problem:
In the form tag, I did :"data-fields" => #fields.to_json.gsub('"',"'").
This produces HTML of this sort:
"data-fields"="[{'name':'id','type':'integer'}]"
And then, in the JS, I retrieve it like this:
$.parseJSON($('form').data('fields').replace(/'/g,'"'))
Related
How can I add hash map element with a key that contains "-"?
Like this:
<%= button_to_function 'Cancel','cancelRemove("cancelEmail")', :data-dismiss=>'modal', :class=>'btn' %>
I get an error:
undefined local variable or method 'dismiss' for #<ActionView::Base:0x3482fed>
While :'data-dismiss' works, with data attributes you can also do
:data => { :dismiss => 'modal' }
Additional data-prefixed html attributes can be included in the same hash. So for example on another link you might do:
:data => { :remote => true, :method => 'delete' }
which would add to the link the html attributes data-remote="true" data-method="delete".
While the hash syntax is less compact for a single attribute, it's nice when you've got more than one html5 data attribute. And it's arguably a bit more rails-ish.
Just rename it to:
<%= button_to_function 'Cancel','cancelRemove("cancelEmail")', :'data-dismiss'=>'modal', :class=>'btn' %>
I'm currently working on a tour interface that guides new users around my site. I have a Tour model that has many TourStops, each of which contains information about a section of the site.
Basically, I'd like to write a function for the Tour model that -- when passed the number of a TourStop -- generates the correct class and data attribute for the HTML element it's attatched to. For example, I'd like
<%= link_to image_tag("new_button.png", tour.stop_data(1), :title => 'Add new asset'), new_asset_path %>
to call a function and return something like
def stop_data(order)
" :class => '#{tour_stops.find_by_order(order).name}',
:data => '{:order => order}'"
end
creating a link_to tag like:
<%= link_to image_tag("new_button.png", :class => 'tour_stop_1',
:data => {:order => 1}, :title => 'Add new asset'), new_asset_path %>
The above code doesn't work. Is something like this even possible? If not, what's a better approach I might take?
The image_tag accepts two parameters. A source, and a options Hash.
What you are trying to do is squeezing your return value from stop_data into this options Hash.
In order to get this to work, you first, need to return a Hash from stop_data, and second, make sure you pass only two arguments to image_tag - the source, and the options.
First:
def stop_data(order)
{
:class => tour_stops.find_by_order(order).name,
:data => { :order => order } # you may need order.to_json
}
end
Second:
link_to image_tag("new_button.png", tour.stop_data(1), :title => "Add new asset"), new_asset_path
This looks like it will work, but it won't, since your'e passing three parameters to image_tag.
When you do the following:
image_tag("new_button.png", :class => "tour_stop_1", :data => { :order => 1 }, :title => "Add new asset")
It looks like you're passing even 4 parameters to image_tag, but in fact they are only two. In Ruby, when the last parameter of a method is a Hash, you don't need to wrap the Hash key/value pairs in curly braces ({}), so the example above is essentially the same as
image_tag("new_button.png", { :class => "tour_stop_1", :data => { :order => 1 }, :title => "Add new asset" })
Now, to get your helper to work with image_tag, you need to merge the options, so they become only one Hash.
link_to image_tag("new_button.png", tour.stop_data(1).merge(:title => "Add new asset")), new_asset_path
Again, we're omitting the curly braces when calling merge, because it's only (and therefore last) parameter is a Hash. The outcome is the same as:
tour.stop_data(1).merge({ :title => "Add new asset" })
I have a view on my current project which does something like the following(in haml):
-#horses.each do |horse|
= render :partial => 'main/votingbox', :locals => {:horse => horse}
The in the _votingbox.html.haml file I have the following:
%div.votingbox
%span.name= horse.name
%div.genders
- if horse.male
%img{:src => 'images/male.png', :alt => 'Male'}
- if horse.female
%img{:src => 'images/female.png', :alt => 'Female'}
%div.voting_form
= form_for(Vote.new, {:url => horse_vote_path(horse)}) do |f|
= f.label :comment, "Your opinion"
= f.text_field :comment
...
a bunch of labels and input elements follow generated using the form helpers
This will generate working code but it does generate forms with the same ids for all the form elements which makes the HTML invalid once the votingbox partial is rendered a second time.
My first guess at fixing this was to specify a unique :id to form_for but that only applies to the form tag generated by form_for and not any of the tags inside the form_for block.
One definite solution to this problem is to go through and manually define my own unique ids on form_for and all the form elements I use. This is more work than I had hoped for.
Is there an easier or cleaner way to get unique ids in a similar format to the way Rails currently generates them on all my form elements?
I have removed the original answer as it is totally irrelevant to the updated version of the question.
Update: So now we know that you have an unsaved ActiveRecord object passed to the form_for call, the answer becomes simple: You can override any parameter that form_for generates. That includes the element id. And fields_for sets the context for a specific record.
= form_for(Vote.new, :url => horse_vote_path(horse), :id => dom_id(horse, 'vote')) do |f|
= f.fields_for horse, :index => horse do |fh|
= fh.text_field :whatever
…
You can override the autogenerated ids and names of all form_for content with :as like the following:
= form_for(Vote.new, :as => horse.name, {:url => horse_vote_path(horse)}) do |f|
= f.label :comment, "Your opinion"
= f.text_field :comment
So if a given horse.name is foobar, it will generate a comment field whose id is foobar_comment and name is foobar[comment]
But remember to make sure that the dynamic parameter is acceptable as an html id, a horse.name like hor$e is not acceptable as an html id and therefore might break something.
P.S: Sorry for answering very late, but at the time the question was asked, I haven't had learnt anything at all about rails! hope that might help someone out there!
In my Rails app, I need to set a value for a custom data-* attribute on an anchor tag. However, hashes can't have hyphens if I'm not mistaken. I essentially want to do this:
<%= link_to 'Example', example_path, :class => 'something', :data-id => '15' %>
:data-id is not valid, however. What can I do to work around this?
IIRC, for such purposes hashes and strings are equivalent, so you can use "data-id" instead of :data-id. Never checked for this particular method, though, so no guarantees.
I think in Rails 3 you can do
link_to "Click Here", root_path, :data => { :id => #model.id }
for all data attributes.
Is there a way to generate both a Javascript function call and an Ajax call in the same observe_form tag? For example, something like this:
<%= observe_form 'user_filter_form', :url => { :action => :process }, :function => :fix_fields %>
Thanks!!
Your best bet here is to dig into the actual JavaScript instead of relying on the helpers. The helpers can only get you so far. What you want is something along these lines:
<script type="text/javascript">
new Form.EventObserver('user_filter_form', function(element, value){
fix_fields();
new Ajax.Request("/YOUR_CONTROLLER/process");
}
</script>
However, if you really want to rely on the Rails helpers you can do something like:
<%= observe_form 'user_filter_form', :function => "fix_fields(); #{remote_function(:url => { :action => :process })}" %>
Use :before or :after options instead of :function, depending on whether you want your function called before of after the Ajax request.
See documentation of link_to_remote helper for common options that can be passed to all the Ajax helpers like observe_form