I'm rendering a form with serialized attributes. The attribute serialization works fine under normal usage, but now i'm trying to serialize a hash. The view code looks like the following
<%= #item.seasonality_of_sales_pct.each do |key, value| %>
<%= eval("f.label :'seasonality_of_sales_pct[:#{key}]'") %>
<%= eval("f.text_field :'seasonality_of_sales_pct[:#{key}]'") %>
<% end %>
The error I'm getting is undefined method 'seasonality_of_sales_pct[:January]' for #<Item:0x007f01083edd38>. However, the line that is throwing the error is the second eval. The first eval evaluates just fine. I'm baffled as to why this might be happening.
In the controller, I am setting up an attribute like the following
#item.seasonality_of_sales_pct = {January: nil, February: nil, March: nil, September: nil}
Another question that could maybe be answered in the comments is: How bad does this code smell? I'm not sure how the rails community feels about metaprogramming like this. It hurts me a bit to do it, but seems to work most of the time
When you use form_for and then use f.text_field :some_attribute_name then the object you are building the form for (in your case #item) mush have an attribute named some_attribute_name.
You get this error because #item has no attribute or method named seasonality_of_sales_pct[:January]
I also would point out that there is no reason to use eval in your form, it is a serious security risk, as code can be injected.
I wanted to be a bit more thorough than Khaled's answer, which was sort of right. The reason that the first eval statement didn't cause the error was because f.label doesn't care what you give it. <%= f.label :fake_stuff %> will just create a label called Fake Stuff. I'm still not quite sure why the attribute didn't work. If I had f.text_field :seasonality_of_sales_pct, I got a text box full of my hash. Also, I got the labels to display the correct values.
I absolutely did not need to use evals here (I can hope it was only a moment of weakness). Just do
<%= f.text_field :'seasonality_of_sales_pct[:"#{key}"]' %>
Related
I have a set of 2 fields (title, description) and some locales (English,Swedish) for translation.
When you visit the page you can only see English set fields. But, user must be able to provide additional translations (if he wants). For that purpose I use "globalize3" and "batch_translations" (https://github.com/fidel/batch_translations) gems.
Language selection is done like a dropdown list. Once you select a language, new set of fields should appear just below the previous set.
Problem itself kinda resembles the one Ryan covered in his screencasts: http://railscasts.com/episodes/197-nested-model-form-part-2
BUT, there is one major difference - forms must be translated as well.
At first, I thought that everything is OK, I won't have any problems passing a form builder reference to my controller's remote action, that is responsible for rendering the partial with selected locale and embedding it.
But, it turned out that there is no possibility to pass the reference by object_id (Garbage Collector destroy's it).
Then I found that you can instantiate the FormBuilder in controller, something like this:
f = ActionView::Helpers::FormBuilder.new(:name, #object, view_context, {}, nil)
If I do so, only first-order fields are working, like this: f.text_field
But, globalize3 and batch_translations are using nested_attributes:
<% f.globalize_fields_for locale do |g| %>
g.text_field :title
g.text_area :description
<% end %>
And for some reason (I think it is because of the incorrect view_context), system throws an error:
ActionView::Template::Error (undefined method `<<' for nil:NilClass)
Any good solution to this problem ? Thanks!
How would i get <%= "#obj#{count}" %> to actually display the variable value in the DOM instead of #obj0, #obj1, etc
I've got variable #obj0, #obj1, #obj2, etc that I need to display
A couple of ways.
First, the most correct (IMHO) is to put all your vars to an array and index that.
arr = [#obj0, #obj1, #obj2]
<%= arr[count] %>
Another option is to use eval. Avoid this (unless you really know what you're doing).
<%= eval("obj#{count}") %>
I am not quite sure what you are going for but I think you want
<%= #obj.count %>
Is there a way to send an extra parameter through a form in rails 3?
For example:
<%= form_for #post do |f| %>
<%= f.hidden_field :extraparam, :value => "22" %>
<% end %>
but lets say :extraparam isn't part of the post model..
I have an unknown attribute error in the create method of the controller when I try this, any ideas?
(I want to use the param value itself in the controller for some extra logic)
Call hidden_field_tag directly. See: http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-hidden_field_tag
These helpers exist for all the major form field types, and are handy when you need to go beyond your model's methods.
The following worked for me in passing extra parameters from the view back to the controller that were a part of my model and not part of my model.
<%= hidden_field_tag :extraparam, value %>
Example usage
<%= hidden_field_tag :name, "John Smith" %>
Ya Paul is right. Hidden_field is associated with your model whereas the extra _tag fields are not. I'm not sure of your needs but It's generally recommended in the RoR community to avoid passing a ton of hidden_fields like you might do in a php application.
Ive seen some code where ids were getting passed around in hidden fields which rails takes care on its own if you know the best practices and take full advantage of the framework. Of course I'm just saying this as general info as there are sometimes better ways at accomplishing the same functionality. Good luck on your apps.
we use
(1..10).each do |i|
p i
end
so that a value is "yield" to i in a block...
but what about
<% form_for #story do |f| %>
<%= f.text_field :name %>
<% end %>
there is no loop at all... why do we need to make it look like a loop? Can't we do it without making it look like a loop? (write in another way)?
Also, must be use a Story instance here? Can't we just use :story and achieve the same result? The #story instance is just newly created and has no data at all -- does it actually help creating the form? Can't :story suffice already? thanks.
Update:
is the idea similar to: (just pseudo code)
with_model_give_form (#story) do |f|
f.begin_form
f.text_field :name
f.end_form
end
so i think the block method will save the begin_form and end_form because it automatically add the begin and end before and after calling the block. is that the main benefit?
I think you have misunderstood the way Ruby works in this case.
It is true that you put everything in a block, but it has nothing to do with a loop.
What you actually do in
(1..10).each do |i|
p i
end
is creating the block {|i| p(i); } and sending it to the function Range.each()
It is the same thing with the form_for. What you actually do is creating the block {|f| puts( f.text_field(:name)); } and passing it to the form_for function. (now it doesn't use puts, but some string concatenation, but you get the idea).
So it's basically not a loop, but a lambda function that will be called several times when called in a loop.
Here is some more information about blocks
Update:
Regarding your update. In a way, yes, that is the main benefit. It is not completely true, but you get the idea. The purpose for that block (and a lot other) are to make the code easier to read and understand. And also to speed up the development.
Dividing code into blocks have always been sought for, just look at the concept of functions, classes and other statements.
for instance, the form_for is mostly for speeding up the development. Yes, it creates the start and end tags, but that is not all.
<% form_for #story do |f| %>
<%= f.text_field :name -%>
<% end %>
Could actually be written something like:
<form action="<%= polymorphic_edit_path(#story) -%>"
id="<%= #story.class_name.underscore -%>">
<%= text_field :story, :name -%>
</form>
of course, it wouldn't exactly be like that, this is a lot simplified and the form_for function can do a lot more than that, but at least you should get the picture.
A "yield" does not always imply a loop - it's more of a "block" concept, it just happens to manifest itself in more of a iteration / loop context. The more you think about yield being a loop construct the more you pigeon hole yourself and prevent yourself from truly learning the awesomeness of blocks.
As for :story, yeah, it is kind of lame. You would think that Rails would just constantize it and infer its model from there. You could also just also Story.new in your view, versus doing that in your controller, but yeah, it's the same thing.
Is there a way to use fields_for with in a form without having a scope?
For example:
<% fields_for "user[]" do |x|
<%= x.text_field :name %>
<% end %>
Without the user model being loaded in memory?
I got it working using territory[user][][name], but I would like to keep it in ERB.
I think the answer would be 'no', since those form_for and fields_for would try to determine default value from that given instance variable.
However, I think if you want to lower memory usage from loading that model, you might try to create a mock-up model to return nil values, and create a instance object from that one instead.
is there any specific reason you need to use form_for specifically? Its really designed to be used with an instantiated model object.
Alternatively, why don't you just use the regular form helper tags. You can define it as follows:
<%form_tag :my_form do %>
<%= text_field_tag :foo, :bar %>
<%end%>
You may want to check the documentation for action view to see how it all works.