Rails Access field values that are not from model on controller - ruby-on-rails

I have a form for some model, inside this form I have some text_fields and hidden_fields
that i need to use in the controller but that are not from the model.
this is a simplified version of it
<%= from_for #user do |f| %>
<%= f.text_field :name %>
<%= hidden_field :photo, value: 'blabla' %>
<%= text_field :type %>
<% f.submit %>
Lets say that the :photo and :type parameters are not in the model user but i need them to decide how to create the user.
they are going in the params hash, but all messed up. How do I access their value?
Thank you

hidden_field_tag "photo", "photo_value"
=> <input id="photo" name="photo" type="hidden" value="photo_value" />
Then in your controller:
#hidden_photo = params[:photo]
Whenever you are working with a form and want a value not associated with a model or object, then use the helpers ending in "*_tag"

Related

RoR : Mongoid and form create hash

Simple question for Rails gurus. Why I do have to use the following statement to insert a new Mongoid document : params[:video][:description] in the following create method of my VideosController? Why I can't use the params[:description] from the POST form? If I use it, the value becomes nil.
def create
#video = Video.new(
:title => params[:video][:title],
:description => params[:video][:description]
)
if #video.save
render 'success'
else
render 'error'
end
end
Here is the Video.rb class :
class Video
include Mongoid::Document
field :title, type: String
field :description, type: String
validates_presence_of :title
validates_presence_of :description
acts_as_url :title
end
And finaly the form view :
<%= form_for #video do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<p/>
<%= f.label :description %>
<%= f.text_field :description %>
<%= submit_tag("Enqueue video") %>
<% end %>
I don't quite get why the form input are video[description] and not just description as expected :
<label for="video_title">Title</label>
<input id="video_title" name="video[title]" type="text" />
<p/>
<label for="video_description">Description</label>
<input id="video_description" name="video[description]" type="text" />
When you are using form_for:
Creates a form that allows the user to create or update the attributes
of a specific model object.
In your case, Video model. To understand Rails convention:
<%= form_for #video do |f| %>
...
<%= f.text_field :description %>
...
Which results in an html tag whose name attribute is video[description]. This means that when the form is submitted, the value entered by the user will be available in the controller as params[:video][:description].
The params variable is an instace of ActiveSupport::HashWithIndifferentAccess, like a Hash with a small difference, according to documentation:
This class has dubious semantics and we only have it so that people
can write params[:key] instead of params[‘key’] and they get the same
value for both keys.
Your params is something like:
{"utf8"=>"✓",
"_method"=>"post",
"authenticity_token"=>"xxx",
"video"=>
{"description"=>"Video desc"}
}
Where "video" or :video is one of the keys of the Hash. So, params[:video] is equivalent to params.fetch("video") which value is {"description"=>"Video desc"}. As you can see the value is another Hash. Finally to get the value of the description you have to params[:video][:description] (The Rails way) or params.fetch("video").fetch("description"), which value is "Video desc".
fetch is a Ruby method of Hash: "Returns a value from the hash for the given key."
Taking this into account:
Video.new(params[:video]) = Video.new(:description => "Video desc") = Video.new(:description => params[:video][:description])
It's easier to use conventions, but for sure you can have params[:description] (just in case):
<%= form_for #video do |f| %>
...
<%= text_field_tag :description %>
...
Note that I'm using text_field_tag instead of f.text_field. In this case the html tag name will be description in the params Hash you will receive { "description" => 'Video desc" }...
Take a look to Rails API documentation to understand different helpers, etc. And also review your server's log.
If you want to use video[:description]. Create your form like this
<%= form_for #video do |f| %>
....
<p/>
<%= f.label :description %>
<%= f.text_field :description, :name => "description" %>
....
<% end %>
Rails form_for helper name the input elements such that it becomes easy to push them into model attributes in one go like this
#video = Video.new(params[:video])
so that you don't have to do it like the way you have done
#video = Video.new(
:title => params[:video][:title],
:description => params[:video][:description]
)

Rails how to get query string from get action in post action?

I have a url like this http://example.com/myController?key=12345
In my controller myController, i can access the key value with params[:key], but when i submit a form, i want to get that same key in the create method, but the params[:key] is null.
How can i access params[:key] in my post action create?
You might indeed add a hidden field.
If you find yourself adding many of those because you need to have the value available in more and more actions, consider setting it within the session as (e.g.) session[:current_key]
You can pass the info along by a hidden_field_tag. So your code would be like:
<%= form_for #model do |f| %>
<%= hidden_field_tag 'key', params[:key]
# other form code
<%= f.submit %>
<% end %>
You can add a hidden field to your form and set its value to params[:key]. Then it will be available in the params you get from the form.
If you're using Simple Form:
<%= simple_form_for #model do |f| %>
...
<%= f.input :field_name, :as => :hidden, :input_html => { :value => params[:key] } %>
<%= f.button :submit %>
<% end %>
Add a new hidden field to pass via params, when you submit the form your action is changed or called again params hash is recreated; what you can do is pass the value via hidden field in the form as follow,
<%= simple_form_for #model do |f| %>
# your remaining form fields
<%= f.input :field_name, as: :hidden, :input_html: { value: params[:key] } %>
<%= f.button :submit %>
<% end %>

How to prefill nested form fields

I have a simple nested form using the 'nested_form' gem.
It looks like this:
<%= nested_form_for #user do |f| %>
<%= f.text_field :username, :size => 25 %>
<%= f.fields_for :teams do |team_form| %>
<%= team_form.label :team_name, 'Name of your team' %>
<% end %>
<%= f.submit :value =>'submit' %>
<% end %>
Now I want to prefill the fields in my new-action. While it's easy to fill the username-field with #user.username = "someone" I have no idea how to access the first nested field "team_name" in the nested "team_form".
In the html the field looks like this:
<input id="user_teams_attributes_0_team_name" type="text" name="user[teams_attributes][0][team_name]">
Any ideas how to prefill this nested field?
Typically build can be used for this in your controller (as it doesn't cause a save on the #user object), appending new Team instances to the :teams collection on the #user object. In your action
#user = User.new
#user.teams = [ Team.build(...) ]
where ... contains the default attributes for #user.teams.first that will be displayed in the nested form.

Is there any way for the controler to get values from a form in your view before it is saved?

I assume the values must be passed back to the controller for use, but everything I have tried seems to only get values that have already saved in the db.
When a form is submitted, the controller will always have access to a hash called "params", which will contain all of the submitted data.
For example, if your form contains a textbox with a name "foo"
<input type="text" name="foo" />
the value can be retrieved in the controller using
fooValue = params[:foo]
You can use this to build a new instance of a model, containing the submitted values from the form as follows:
in your form:
<% form_for :person, #person, :url => { :action => "create" } do |f| %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<%= submit_tag 'Create' %>
<% end %>
then, in your controller:
#newPerson = Person.new(params[:person]; #this will pass the whole group of values within that person form to the "new" method

Multiple forms for the same model in a single page

On the front page of my rap lyrics explanation site, there's a place where users can try explaining a challenging line:
alt text http://dl.dropbox.com/u/2792776/screenshots/2010-02-06_1620.png
Here's the partial I use to generate this:
<div class="stand_alone annotation" data-id="<%= annotation.id %>">
<%= song_link(annotation.song, :class => :title) %>
<span class="needs_exegesis"><%= annotation.referent.strip.gsub(/\n/, "\n <br />") %></span>
<% form_for Feedback.new(:annotation_id => annotation.id, :created_by_id => current_user.try(:id), :email_address => current_user.try(:email)), :url => feedback_index_path, :live_validations => true do |f| %>
<%= f.hidden_field :annotation_id %>
<%= f.hidden_field :created_by_id %>
<p style="margin-top: 1em">
<%= f.text_area :body, :rows => 4, :style => 'width:96%', :example_text => "Enter your explanation" %>
</p>
<p>
<% if current_user %>
<%= f.hidden_field :email_address %>
<% else %>
<%= f.text_field :email_address, :example_text => "Your email address" %>
<% end %>
<%= f.submit "Submit", :class => :button, :style => 'margin-left: .1em;' %>
</p>
<% end %>
</div>
However, putting more than one of these on a single page is problematic because Rails automatically gives each form an ID of new_feedback, and each field an ID like feedback_body (leading to name collisions)
Obviously I could add something like :id => '' to the form and all its fields, but this seems a tad repetitive. What's the best way to do this?
If you don't want to change your input names or your model structure, you can use the id option to make your form ID unique and the namespace option to make your input IDs unique:
<%= form_for Feedback.new(...),
id: "annotation_#{annotation.id}_feedback"
namespace: "annotation_#{annotation.id}" do |f| %>
That way our form ID is unique, i.e. annotation_2_feedback and this will also add a prefix, e.g. annotation_2_, to every input created through f.
Did you consider nested_attributes for rails models? Instead of having multiple new feedback forms where each is tied to an annotation, you could have multiple edit annotation forms where each annotation includes fields for a new feedback. The id's of the generated forms would include the annotations id such as edit_annotation_16.
The annotation model would have a relationship to its feedbacks and will also accept nested attributes for them.
class Annotation < ActiveRecord::Base
has_many :feedbacks
accepts_nested_attributes_for :feedbacks
end
class Feedback < ActiveRecord::Base
belongs_to :annotation
end
You could then add as many forms as you want, one for each annotation. For example, this is what I tried:
<% form_for #a do |form| %>
Lyrics: <br />
<%= form.text_field :lyrics %><br />
<% form.fields_for :feedbacks do |feedback| %>
Feedback: <br/>
<%= feedback.text_field :response %><br />
<% end %>
<%= form.submit "Submit" %>
<% end %>
<% form_for #b do |form| %>
Lyrics: <br />
<%= form.text_field :lyrics %><br />
<% form.fields_for :feedbacks do |feedback| %>
Feedback: <br/>
<%= feedback.text_field :response %><br />
<% end %>
<%= form.submit "Submit" %>
<% end %>
And the quick and dirty controller for the above edit view:
class AnnotationsController < ApplicationController
def edit
#a = Annotation.find(1)
#a.feedbacks.build
#b = Annotation.find(2)
#b.feedbacks.build
end
def update
#annotation = Annotation.find(params[:id])
#annotation.update_attributes(params[:annotation])
#annotation.save!
render :index
end
end
I had this same issue on a site I'm currently working on and went with the solution you mention at the bottom. It's not repetitive if you generate the ID programmatically and put the whole form in a partial. For example, on my site, I have multiple "entries" per page, each of which has two voting forms, one to vote up and one to vote down. The record ID for each entry is appended to the DOM ID of its vote forms to make it unique, like so (just shows the vote up button, the vote down button is similar):
<% form_for [entry, Vote.new], :html => { :id => 'new_up_vote_' + entry.id.to_s } do |f| -%>
<%= f.hidden_field :up_vote, :value => 1, :id => 'vote_up_vote_' + entry.id.to_s %>
<%= image_submit_tag('/images/icon_vote_up.png', :id => 'vote_up_vote_submit' + entry.id.to_s, :class => 'vote-button vote-up-button') %>
<% end -%>
I also had the same issue but wanted a more extensible solution than adding the ID to each field. Since we're already using the form_for ... |f| notation the trick is to change the name of the model and you get a new HTML ID prefix.
Using a variant of this method: http://www.dzone.com/snippets/create-classes-runtime (I removed the &block stuff)
I create a new model that is an exact copy of the model I want a second form for on the same page. Then use that new model to render the new form.
If the first form is using
#address = Address.new
then
create_class('AddressNew', Address)
#address_new = AddressNew.new
Your ID prefix will be 'address_new_' instead of 'address_' for the second form of the same model. When you read the form params you can create an Address model to put the values into.
For those stumbling here, looking for the solution for Rails 3.2 app, look at this question instead:
Rails: Using form_for multiple times (DOM ids)

Resources