I decided to start a little project in rails 3 and I am a little bit stuck on a form... Where can I specified the f.submit action should go to a special controller / action ?
The code in the form is:
<%= form_for #user, :url => { :action => "login" } do |f| %>
<div class="field">
<%= f.text_field :email %><br />
<%= f.text_field :password %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
User is defined as #user = User.new in "index" method of "home_controller".
but I have the error:
No route matches {:controller=>"home", :action=>"login"}
as soon as I run http://0.0.0.0:3000
I am very sorry for this newbee question but I cannot find the routing details (I worked a little bit with rails a couple of years ago but...)
Thanks,
Luc
You don't need to specify any action for f.sumbit.
First of all, you need to make sure you put
resources :users
(for example)
in your routes.rb
then if you want to create a user
put
def new
#user = User.new
end
in your users_controller so you have a page to create new user
or you can put #user=User.new anywhere you like, remember to set
the route correctly
then
def create
#user = User.new(params[:id])
if #user.save
sign_in #user
redirect_to #user
else
render 'new'
end
end
is the part that does real work after you hit on submit
the actual part that connect your form with everything else is this line
<% form_for #user do |f| %>
you can change user to other object, and you can also edit form using update action in a controller.
Hope you got the idea
Whenever you use REST objects, the mere:
form_for #article
is enough for the form to find the proper path.
Otherwise, you can use helpers this way:
form_tag(:controller => "people", :action => "search", :method => "get", :class => "nifty_form")
More info here: http://edgeguides.rubyonrails.org/form_helpers.html
Related
I would like to have a drop down menu with a list of all the user names in the db. From there, I would like the user to choose his/her name and be able to click login and be taken to their respective page. At this point, a password is not needed. Currently, I have the following:
controller:
def login
#user = User.new
#users = User.all
# #user = User.find_by_id(:id)
# redirect_to user_path(#user)
end
view:
<%= form_for #user, url: '/login', html: {method: 'get'} do |f| %>
<%= f.label "Name" %>
<br/>
<%= select_tag :user, options_for_select(#users) do |users| %>
<%= link_to users.name, users %>
<% end %>
<br/>
<br/>
<%= f.submit 'Login' %>
<% end %>
I cannot seem to link the user to their path and also, i want to show the users name in the drop down menu. Currently, it shows a hexidecimal pointer.
Thank you in advance.
You shouldn't be making a new User object here: you just want to load one out of the database. What you want to do in the controller is just to set current_user to be one of the existing users, right?
Also you've got the form submitting back to the action which loads the form in, which seems weird. I would make it submit to a new action, like "set_current_user" which is a POST action.
in your login template:
<%= form_tag '/set_current_user' do %>
<%= f.label "Name" %>
<br/>
<%= select_tag "user_id", options_for_select(#users.collect{|user| [user.name, user.id] } %>
<br/>
<br/>
<%= submit_tag 'Login' %>
<% end %>
in the controller (you'll need to amend routes.rb to make the '/set_current_user' go to this action) you then need to set something which will keep the user logged in. The traditional way to do this is via session[:user_id], and to have a method current_user which uses this.
def set_current_user
session[:user_id] = params[:user_id]
redirect_to "/" and return
end
Your initial approach is reminiscent of how this sort of thing is normally handled, wherein you do have a form_for, but it's for a UserSession object rather than a User object.
I've seen this question asked everywhere, but it never solves my problem. Heres my controller:
class UserVacationDaysController < ApplicationController
def new
#user = current_user
#user_vacation_days = UserVacationDay.new
end
def create
#user_vacation_days = UserVacationDay.create(params[:user_vacation_day])
#user_vacation_days.user = current_user
# #user_vacation_days.calculate_work_days
# (another param that holds date range will get passed in)
# puts #user_vacation_days.errors.inspect
if #user_vacation_days.persisted?
flash[:notice] = "Request Sent"
redirect_to dashboard_index_path
request_vacation_days # method from model. model method calls method in employee_mailer
else
flash[:notice] = "Something went wrong, please try again"
render :new
end
end
end
And here is my view (form).
<h2>Request Days Off</h2>
<%= form_for :user_vacation_days, :url => user_vacation_days_path do |f| %>
<div><%= f.label "How much time off would you like to take?" %>
<%= f.number_field :number_of_days %></div>
<div><%= f.label "Argue your case, slave" %>
<%= f.text_area :description %></div>
<div><%= f.submit "Request Time Off" %></div>
<% end %>
The routes for my 2 controller methods are
user_vacation_days POST /user_vacation_days(.:format) user_vacation_days#create
new_user_vacation_day GET /user_vacation_days/new(.:format) user_vacation_days#new
Does anyone have any idea what's going on? I've looked all over the place, and I can't find anything. I can't think of any reason why the controller method wouldn't be found. Thanks!
Instead of <%= form_for :user_vacation_days, :url => user_vacation_days_path do |f| %> what happens if you use <%= form_for #user_vacation_days, :url => user_vacation_days_path do |f| %>
Also, does a User have_many VacationDay? You might want to change to resourceful routes, and have vacation days nested.
config/routes.rb
resources :users do
resources :user_vacation_days
end
in your new action under UserVacationDaysContoller #may want to rename this to just VacationDays since the nesting implies
def new
#user = current_user
#user_vacation_days = #user.vacation_days.build
end
as one of you said in my previous question, i attempted to make a post request.
Here is my login view
<%= form_for :check_validity, :method => "post", :url => {:action => "check_validity"} do |f| %>
<%= f.label :username %>
<%= f.text_field :username %><br />
<%= f.label :password %>
<%= f.password_field (:password)%><br />
<%= f.submit "Submit"%>
<% end%>
Since the check_validity is a post method, i wrote the below code in my post method
def check_validity
#USER = params[:display_command_list][:username]
#PASS = params[:display_command_list][:password]
#HOST = 'hostname'
Net::SSH.start( #HOST, #USER, :password => #PASS ) do|ssh|
#result = ssh.exec!("command")
end
if(#result =~ /somestring/)
redirect_to display_command_list_path({:username => #USER, :password => #PASS})
else
redirect_to denied_access_path
end
end
But when i enter username and password in login page and click on submit button, it goes to this post method and gives me "Missing template authorization/check_validity" error. I included post "authorization/check_validity" in my routes.rb. It seems that i'm missing something very basic here :(. Please let me know why is it not able to redirect to the paths i mentioned instead of looking for check_validity.html.erb
I remember when we scaffold, and click on new post and submit it, it redirects to create method which is a post request and then automatically redirects to show method which is 'get'. How is it able to understand that it should go to 'show' after create? I tried to replicate that here but failed. Please help.
Update: I have seen here and understood that we should not use redirect in a POST method. But how would i use this information and go to denied_acess_path or display_command_list_path from this check_validity method
i think i solved the problem.
In the login method i used the following code
def login
respond_to do |format|
format.html
end
end
When i removed the respond_to block, i was able to execute the code. But i still do not know why this is happening. Is the respond to tag looking for check_validity.html.erb instead of login.html.erb?
I have the following form and controller.
<%= form_tag do %>
<div>
<%= label_tag :Old %>
<%= password_field_tag :old_password %>
</div>
<div>
<%= label_tag :New %>
<%= password_field_tag :new_password %>
</div>
<div>
<%= label_tag :Confirm %>
<%= password_field_tag :confirm_password %>
</div>
<div>
<%= submit_tag "Update" %>
</div>
<% end %>
and the controller:
def change
#user = current_user
#op = params[:old_password]
#np = params[:new_password]
#cp = params[:confirm_password]
if #np == #cp
#user.update_with_password(:password => #np, :current_password=>#op)
if #user.save
flash[:notice] = "Password Successfully Changed"
redirect_to home_path
end
else
#user.errors.add("Incorrect confirmation")
end
end
This is all tied to 'password/change' in the config/routes.rb
The problem is that when I go to /password/change I immediately an redirected to home and receive the "password successfully changed" flash notice. What I take from it is that it is not requiring me to click the submit button in order to pass the parameters. How do I make it so that it waits for the submission of the form before continuing through the controller?
The problem is that you need 2 separate methods. One to show the view and one to handle the form post.
Right now the "change" method in your password_controller is handling the form post so you need a method like "index" to show the form
def index
#move your form to /views/password/index.html.erb or specifically render your 'change' view
end
Then in your markup add the action to your form
<%= form_tag('/password/change') do %>
…
Then in your controller you can specify POST only for the change method
class PasswordController < ApplicationController
verify :method => :post, :only => :change
…
UPDATE
Instead of using the verify method (removed in rails 3) you should either set up your route to be restful (Rails Routing from the Outside In) or you can create a specific route for changing the password like so:
match 'password/change' => 'password#change', :via => :post
The best practice will be to separate these two things into different controller methods. One should be used to simply display the view, while the other should be used to handle the POST request. However, if you're dead set on doing it this way, I believe a solution like this will work:
def change
#user = current_user
#op = params[:old_password]
#np = params[:new_password]
#cp = params[:confirm_password]
if #np && #np == #cp # This checks to see if params[:new_password] is nil
#user.update_with_password(:password => #np, :current_password=>#op)
I'd strongly suggest you separate it out though.
When you render password/change from the browser, params is nil, so #np == #cp always evaluates to TRUE, executes the update, saves, and does the redirect — in fact, if you check I would bet the user's password is being set to nil.
You need to make sure the params are not empty before attempting the update.
Does that help point you in the right direction?
side note: from a code readability standpoint I might recommend just using the variables inline, instead of the instance vars, but that's just my opinion :)
Something weird's happening with my Rails app. When I try to send an update command to one of my controllers, for some reason the submit button appears to be changing some of the params.
I'm using nested resources and setting up races which have participants. Pretty simple. For some reason, though, when I try to update a participant, it changes the value of :race_id to the participant's id (:id).
Though it only does that on update. I seem to be able to create new participants perfectly using the very same form, and so the very same submit button.
Here is some of the relevant code:
_form.rb (used by new and update)
<%= form_for ([:race, #participant]) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p><%= f.submit %></p>
<% end %>
participants_controller.rb
class ParticipantsController < ApplicationController
before_filter :authenticate_user!, :only => [:edit, :update, :destroy, :create, :new]
before_filter :set_up_race
...
def create
#participant = #race.participants.new(params[:participant])
if #participant.save
redirect_to setup_race_path(#race), :notice => "Successfully created participant."
else
render :action => 'new'
end
end
...
def update
#participant = Participant.find(params[:id])
if #participant.update_attributes(params[:participant])
redirect_to setup_race_path(#race), :notice => "Successfully updated participant."
else
render :action => 'edit'
end
end
...
def set_up_race
#race = Race.find(params[:race_id])
end
end
Here's why it seems that parameters are being changed:
If I modify the _form.rb file to include <%= params[:race_id] %>
The screen tells me 3
When I click submit I get:
Couldn't find Race with id=25
Request
Parameters:
{"utf8"=>"✓", "_method"=>"put",
"authenticity_token"=>"4VCZP9sI/iv8n454I8AE76n5vLiwGayuXc1NrPYfzGc=",
"participant"=>{"name"=>"hgdjhgf"}, "commit"=>"Update Participant",
"race_id"=>"25", "id"=>"25"}
(As you can see under parameters, "race_id"=>"25" after I click submit, but the page originally had :race_id =>"3" (proven above, and again if I do anything to make the form crash)).
So the question is, after all of that, why is :race_id changing somewhere between the view and the controller?
EDIT: here's a rake routes output, as per Jeff's request:
http://dylancodes.net/personal/ARTk/images/routes.png
What does the url look like that your form is posting to? Based on your routes, I would expect it to look something like /races/3/participants/25. From what I've read, the line
form_for ([:race, #participant]) do |f|
creates a namespaced route (search for "namespaced" on that page) that would look like /races/participants/25.
Does changing that line to this work for you?
form_for [#race, #particpant] do |f|
That should build the form url as /races/:race_id/participants/:id.