I have some data associated with a model that is in a hash. The hash is generated in the controller: #hash.
What is the proper way to create a form for this data?
I came up with the following code for the view:
<% #hash.keys.each do |key| %>
<div class="field">
<%= f.label key %><br />
<%= text_field_tag "hash_" + key, #hash[key] %>
</div>
<% end %>
This generates the form, but it creates each hash item as a separate variable in the form. This doesn't seem to be the proper way to submit the data back. I would like to get the data back as a hash, and access it with params[:hash].
What is the best way to do this?
Working in Rails 3.07, Ruby 1.9.2.
Thanks.
EDIT: I should have made this clear. This code is inside of a form generated for a model. So, the form needs to submit all the fields for the model, plus the above hash.
Based on this article you should change the name in text_field_tag to
<% #hash.keys.each do |key| %>
<div class="field">
<%= f.label key %><br />
<%= text_field_tag "hash[" + key + "]", #hash[key] %>
</div>
<% end %>
My answer is not strictly on topic but I really recommend you to take a look at http://railscasts.com/episodes/219-active-model. You could use ActiveModel APIs to simulate a model object with Rails 3. Doing that you could simply do something like
<%= form_for(#object) %>
and leaving the populating of your object to Rails APIs.
When you use the helpers that end with _tag that's what happens.
Instead of text_field_tag ... use f.text_field ....
In order to get a hash like params => {:hash => {:field1 => "", :field2 => ""}} you have to pair up form_for with f.input_field_type instead of simply input_field_tag.
See the difference?
Related
I want a form like this, because I just want to use :pass_value to pass value to other properties in controller. But it does not work. Could you please provide a right way to do this?
<% form_for #person do |f| %>
<%= f.text_field :name %>
<%= text_tag :pass_value %>
<%= f.submit %>
<% end %>
No, you can't use a form tag inside a form. But you can use one of:
a) fields_for
if this is a nested model, you can use it something like:
fields_for :widget do |g|
g.text_field :widget_name
end
doc for fields_for: http://apidock.com/rails/ActionView/Helpers/FormHelper/fields_for
b) text_field_tag
if it's just an independent field
<%= text_field_tag :some_value %>
doc for text_field_tag:
http://apidock.com/rails/ActionView/Helpers/FormTagHelper/text_field_tag
you cannnot use form_tag inside another form. But if you want to pass the value of :pass_value actually not as an attribute, try making use of virtual attribute. You can make use of :attr_accessor method.
you can use raw html tags, such as
input type="hidden" name="person[pass_value]" value=#person.pass_value
it's just html form after all
I'm trying to offer teachers a form that will create multiple students at once. It seems that most people tackle this concept with nested attributes, but I'm having a hard time understanding how that would work when I'm only using a single model. This article made it seem possible to achieve this without nested attributes, but my results are not working the way the author suggests. The students array should include one hash for each section of the form. But when I submit the form and check the parameters, only one single hash exists in the array.
Adjusting her approach, I've got this controller:
students_controller.rb
def multi
#student_group = []
5.times do
#student_group << Student.new
end
end
(I'm using an action I've called "multi" because it's a different view than the regular "create" action, which only creates one student at a time. I've tried moving everything into the regular create action, but I get the same results.)
The view:
multi.html.erb
<%= form_tag students_path do %>
<% #student_group.each do |student| %>
<%= fields_for 'students[]', student do |s| %>
<div class="field">
<%= s.label :first_name %><br>
<%= s.text_field :first_name %>
</div>
<div class="field">
<%= s.label :last_name %><br>
<%= s.text_field :last_name %>
</div>
<% end %>
<% end %>
<div class="actions">
<%= submit_tag %>
</div>
<% end %>
The results:
(byebug) params
<ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"3Xpi4XeqXuPs9jQvevy+nvGB1HiProddZzWq6Ed7Oljr3TR2fhx9Js6fN/F9xYcpgfDckCBOC2CoN+MrlFU0Bg==", "students"=>{"first_name"=>"fff", "last_name"=>"ggg"}, "commit"=>"Save changes", "controller"=>"students", "action"=>"create"} permitted: false>
Only one has is included for a student named "fff ggg". There should be four other hashes with different students.
Thank you in advance for any insight.
fields_for is only used in conjunction with form_for. The for is referring to a model, which it expects you to use. Since you're trying to build a form with no model, you have to construct your own input field names.
Don't use fields_for but instead, render each input using the form tag helpers e.g.
<%= label_tag "students__first_name", "First Name" %>
<%= text_field_tag "students[][first_name]" %>
...and so on.
The key is that the field names have that [] in them to indicate that the students parameters will be an array of hashes. You almost got it by telling fields_for to be called students[] but fields_for ignored it because it needs a model to work correctly.
I have a controller named Welcome with view called index.
In my index view i have created a small form as such.
<%= form_for :location do |f| %>
<%= f.label :Longitude %><br>
<%= f.text_field :integer %>
<br>
<br>
<%= f.label :Latitude %><br>
<%= f.text_field :integer %>
<p>
<%= f.submit %>
</p>
<% end %>
In this form the user can enter some integer value for longitude and latitude. Once the user enters value for longitude and latitude. They click submit. Upon submit i would like to store these values in my controller. So i am using the following method where i have two instance variables taking values from the form.
def index
#long = params[:longitude]
#lat = params[:latitude]
end
In my routes.rb I have
get 'welcome/index'
post 'welcome/index'
Please tell me where i went wrong. Also if someone can suggest a better way of doing this also i would appreciate it i am new to rails and i want to learn the correct way of doing things so i don't create bad habits early on.
The reason it's not working is because your fields are both named :integer, and since they share the same name, the browser will only send one value.
So, with your code, if you filled in the first field with 'a' and the second with 'b', your params would contain something like this:
{ location: { integer: "aaa" } }
Which obviously isn't what you want! If your HTML looked more like this (I've stripped the layout stuff to make things clearer):
<%= form_for :location do |f| %>
<%= f.label :longitude %>
<%= f.text_field :longitude %>
<%= f.label :latitude %>
<%= f.text_field :latitude %>
<%= f.submit %>
<% end %>
Then you could access the params in your controller params[:location][:longitude] and params[:location][:latitude]
A good idea to see the difference between the effect of your form vs this form would be to inspect the html. Take a look at the input name attributes, and label for attributes and see how they match up with the params Rails receives. Also, when you post the form, be sure to look in your server log to see the params! :)
After reading your question, I think you want to see how controllers, views and models work. For learning purpose you can generate scaffold and study the generated code.
For example, generate a model GeoLocation, related controller and views by this:
rails g scaffold GeoLocation longitude:string latitude:string
Now fire up rails server and browse http://localhost:3000/geo_locations/new and save your long, lat. I wrote this answer to give you some guidance.
You can follow these excellent books:
The book of Ruby
The Rails 4 Way
I need to get an array of strings from f.text_field and store it into a database.
<div>
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div>
<%= f.label :tags %>
<%= f.text_field :tags%>
</div>
tags is an attribute and it is in an array. Name stores into the database correctly but nothing to tags.
How can i do this?
Thanks
You'll probably want to either parse that on the client side with JS to create an array that gets stored in a hidden field, or something similar. Alternatively, you should pass the raw text to the controller and parse it ruby. You should probably do the latter as you will probably want to sanitize the input.
There is a very good gem available for handling tagging. It's called acts-as-taggable and is found here https://github.com/mbleigh/acts-as-taggable-on
i'm new to MongoDB and unsure how to use the Array-Field-Type.
So i created in my model
field :admins, type: Array
in this field i wanna store all user_ids that are "admins" of the model. But when I try to set this field, it doesnt save the Information in the Array it just simple creates an String with the ID. And due to my constrain that only Admins can edit my filter function
def check_if_admin
unless Agency.find(params[:id]).admins.include?(current_agent.id)
flash[:notice] = "Only possible as Admin."
redirect_to root_path
end
end
gets the error that
"can't convert Moped::BSON::ObjectId into String"
So I tried to initiate my field with in the create def as an array with ID:
#agency.admins = [current_agent.id]
That does the Trick for one user in the Array but how do I add IDs to this field?
When I go into my Edit Form:
<%= form_for(#agency) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :admins %><br />
<%= f.text_field :admins %> <br />
</div>
<div class="field">
<%= f.label :agents %><br />
<%= f.text_field :agents %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And Type in another User_ID by hand, I'm back to my error again.
Anyone knows how to get around that?
Thanks a ton for ur help!
This message means that at some point you stored a string where there should be an ObjectId. Ruby is trying to compare current_agent.id (an ObjectId) with params[:id] (a string).
It seems like you are not converting the input from the text_field in the form to an ObjectID before you push it onto the array.
Take the input from the admins field and make ObjectId's like this:
BSON::ObjectId.new(string_representing_admin_id)
I'm guessing the admins field is a comma separated array of admin _ids and that you are using some _id values that are easy to work with, like a username instead of a generated ObjectId as this would be very burdensome to work with.
In that case you would probably split and strip the input and then make an array of the ObjectIds using a map/select.
It would be much easier to use a select field that displayed usernames for something like this in rails right?
Anyway, show some sample documents from the collection if you need more help.