I am trying to just get an input and send it to controller.
But the params in controller is always nil
View (index.html.erb)
<%= form_tag(:controller => "zip_code_lookup", :action => 'index') do %>
<%= text_field_tag :zip_code, params[:zip_code] %>
<%= submit_tag("go") %>
<% end %>
Controller
class ZipCodeLookupController < ApplicationController
def index
render :text => params[:zip_code].inspect
end
end
You should use params[:zip_code] in your controller, but NOT in your view.
In your index.html.erb view, replace:
<%= text_field_tag :zip_code, params[:zip_code] %>
with:
<%= text_field_tag :zip_code %>
Then, grab the zip_code value using params[:zip_code] in your controller action.
So, your view (index.html.erb)) becomes:
<%= form_tag(:controller => "zip_code_lookup", :action => 'index') do %>
<%= text_field_tag :zip_code %>
<%= submit_tag("go") %>
<% end %>
See this article for some more information on how form_tag works.
Related
Suppose I have a form like below
<%= form_for #uni, :html => {:multipart => true, :honeypot => true} do |uni_form| %>
<% 3.times { #uni.app.build } %>
<%= uni_form.fields_for :apps do |builder| %>
<%= render 'app', uni_form: builder %>
<% end %>
<% end %>
and my app partial is
<div>
<%= uni_form.label :uni_id, "University" %>
<%= uni_form.collection_select :uni_id, #unis, :id, :name, {:include_blank => true} %>
</div>
Now I want the first form code without the loop. Something like this
<%= form_for #uni, :html => {:multipart => true, :honeypot => true} do |uni_form| %>
<% 3.times { #uni.app.build } %>
<%= render 'app', uni_form: builder %>
<%= render 'app', uni_form: builder %>
<%= render 'app', uni_form: builder %>
<% end %>
How can I do this?
Firstly, don't build your associated objects in your view - do it in your controller:
#app/controllers/unis_controller.rb
class UnisConstroller < ApplicationController
def new
#uni = Uni.new
3.times do
#uni.apps.build
end
end
end
Secondly, the fields_for method is your friend here.
You'll gain what you need by using the following:
#app/views/unis/new.html.erb
<%= form_for #uni, :html => {:multipart => true, :honeypot => true} do |uni_form| %>
<%= uni_form.fields_for :apps do |builder| %>
<%= builder.label :uni_id, "University" %>
<%= builder.collection_select :uni_id, #unis, :id, :name, {:include_blank => true} %>
<% end %>
<% end %>
fields_for takes your model's associated objects and automatically creates the fields you need. There is literally no need to "loop" - fields_for does it for you... if you set it up correctly.
The problem you have is you're building your associated objects at runtime, which is not only inefficient & against convention, but I think it will prevent the form_for from recognizing them (which is what allows fields_for to loop through them).
The above code should fix this for you.
I'm new to rails and trying to make a simple site to start learning. When I submit my form, however, the data isn't saved to the db. I'm really not sure what's wrong, I've been trying to figure it out for a while. If I make a record in the rails console and save it, that one successfully shows up in the db (and on the index page).
calculate.rb:
class Calculate < ActiveRecord::Base
attr_accessible :number, :root
end
calculates_controller.rb:
class CalculatesController < ApplicationController
def index
#calculate = Calculate.all
end
def new
#calculate = Calculate.new
end
def create
#calculate = Calculate.new(params[:calculate])
if #calculate.save
redirect_to '/calculates'
else
render 'new'
flash[:notice] = "Didn't work"
end
end
end
new.html.erb:
<%= form_for(#calculate) do %>
<%= label_tag(:number, "Enter the number") %>
<%= text_field_tag :number %>
<%= label_tag(:root, "root") %>
<%= text_field_tag :root %>
<%= submit_tag("Submit") %>
<% end %>
if you are using form_for, use the form_for syntax
<%= form_for(#calculate) do |form| %>
<%= form.label :number %>
<%= form.text_field :number %>
<%= form.label :root %>
<%= form.text_field :root %>
<%= form.submit "Submit" %>
<% end %>
this will automatically handle the routes if the #calculate is new object it will submit it to create or if it is already saved it will send a put request to edit action
Ah hah! I updated my view to:
<%= form_for #calculate, :url => { :action => "create" } do |f| %>
<%= f.label :number %>
<%= f.text_field :number %>
<%= f.label :root %>
<%= f.text_field :root %>
<%= submit_tag("Submit") %>
<% end %>
And now it works. Awesome.
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Passing only two variables between controller and view - best practice?
There is my action:
def list
#codes = Code.order("created_at")
#languages = Language.order('name').collect {|l| [l.name, l.coderay]}
end
There is my view(I removed some lines):
<% #codes.each do |code| %>
<div class="code">
<%= link_to code.title, :action => 'show', :id => code.id %>
<% if code.author %>
#<%= code.author %>
<% end %>
</div>
<% end %>
<%= render :partial => 'shared/error_messages', :locals => {:object => #code} %>
<%= form_for :code, :url => {:action => 'create' }, :html => {:multipart => true} do |f| %>
<%= f.text_field :title %><br />
<%= f.text_area :content %><br>
<%= f.select(:language, #languages, {:selected => 'text'}) %>
<%= f.text_field :author %><br>
<%= f.submit "Submit code" %>
<% end %>
There are 3 variables in it: #codes(list of posts), #code(current post, used in another action) and #languages.
My IDE writes:
At most two instance variables should be shared between controller and
view
This inspection warns if there are more than two instance
variables shared between a controller and a view. A controller should
only manage one instance variable, plus a second one for the
current_user variable.
Usually I share more variables between Controller and View(in PHP), sometimes 10+.
How it's done in Rails?
You can save an instance var by making languages a helper:
def languages
Language.order('name').collect {|l| [l.name, l.coderay]}
end
Its a guideline some developers follow some of the time.
But I would read up on Rails Routing a bit more. Understanding how Rails routing works should give you a better idea on how to structure your code.
http://guides.rubyonrails.org/routing.html
I modified your code a bit, not tested. But hopefully gives you some good ideas.
Controller:
def new
#code = Code.new
#codes = Code.order("created_at")
end
def create
#code = Code.new(params[:code])
if #code.save?
# Do your thing.
else
# render your :new action passing your #code variable
end
end
View:
<% #codes.each do |code| %>
<div class="code">
# Use Rails Routing - In console, type rake routes to get list of routes.
<%= link_to code.title, code_path(code.id) %> # example.
<% if code.author %>
<%= code.author %>
<% end %>
</div>
<% end %>
<%= render 'shared/error_messages', :object => #code %>
<%= form_for #code, :html => {:multipart => true} do |f| %>
<%= f.text_field :title %><br />
<%= f.text_area :content %><br>
# language_list = helper method.
<%= f.select(:language, language_list, {:selected => 'text'}) %>
<%= f.text_field :author %><br>
<%= f.submit "Submit code" %>
<% end %>
My use case is a bit more complicated than the one shown in RailsCasts.
I get an unknown attribute: user error.
Issues and users are related by a many-to-many through another model.
I HAVE specified the accepts_nested_attributes_for in my Issue model.
My view code:
<% semantic_form_for #issue do |form| %>
<% form.inputs do %>
<%= form.input :description, :input_html => { :rows => 5, :cols => 1, :class => 'autogrow' } %>
<%= form.input :location %>
<%= form.input :issue_type %>
<% end %>
<% form.inputs :for => :user do |user_form| %>
<%= user_form.input :email %>
<% end %>
<% form.buttons do %>
<%= form.commit_button "Submit" %>
<% end %>
<% end %>
My Controller code:
def create
#issue = Issue.new(params[:issue])
if #issue.save
flash[:notice] = "Thank you"
else
render :action => 'new'
end
end
Any ideas?
Thanks!
Try using #user instead of :user in the user_form.
I have a partial that contains a form:
<% form_for :message, :url => { :action => "create" }, :html => { :id => 'form' } do |f| %>
<%= f.error_messages %>
<%= f.label :title, "title" %>
<%= f.text_field :title %>
<%= f.label :tag, "tag" %>
<% if controller.controller_name == "tags" %>
<%= f.text_field :tag_list, :value => #title %>
<% else %>
<%= f.text_field :tag_list %>
<% end %>
<%= f.label :name, "name" %>
<%= f.text_field :name %>
<%= f.label :email, "email" %>
<%= f.text_field :email %>
<%= f.label :title, "message" %>
<%= f.text_area :content %>
<%= f.submit 'submit' %>
<% end %>
I'm using this in two controllers: messages and tags. It works fine in the messages controller but not in the tags controller. When it's rendered in tags#show it autofills the tag field. When a message is submitted from tags#show I'm redirected to the root of the website with a flash error "Tag does not exist."
tags controller:
class TagsController < ApplicationController
before_filter :redirect_if_doesnt_exist#, :only => :show
def show
#title = Tag.find(params[:id]).name
#tag = Tag.find(params[:id])
#entries = Entry.paginate(Entry.find_tagged_with(#tag),
:page => params[:page], :per_page => 10, :order => "name")
#messages = Message.paginate(Message.find_tagged_with(#tag),
:page => params[:page], :per_page => 10, :order => "updated_at DESC")
#related_entries = Entry.tagged_with(#tag, :on => :tags)
#related_tags = #related_entries.collect{|x|x.tags}.flatten.uniq
#related_tags.delete(#tag)
end
private
# Redirect if requested tag does not exist
def redirect_if_doesnt_exist
#tag = Tag.find(params[:id]) rescue nil
if #tag.nil? # maybe "or #tag.empty?" could solve the empty tag issue
flash[:error] = 'Tag does not exist.'
redirect_to '/'
end
end
end
In case it isn't clear: The partial is shown in the view, the form within it just doesn't submit the data from the tags controller and is redirected. The partial works fine from the messages controller. This is a Rails 2.3.x application.
Thank you for reading my question, your time is appreciated.
Your problem is the URL of the form partial is only the action:
<% form_for :message, :url => { :action => "create" }, :html => { :id => 'form' } do |f| %>
If you include this in a view that isn't under messages_controller, it'll call the wrong action. If you include this ina a tags view, it'll try to call the create action for tags_controller instead.
It'll probably work if you just add the controller too:
<% form_for :message, :url => { :controller => :messages, :action => :create }, :html => { :id => 'form' } do |f| %>