Reputation: 2129
I'm learning Rails so please pardon my amateur mistakes, but I've been stuck for about an hour or two and have made negative progress.
Goal:
From the user
profile
view, link to a form that allows thisuser
to change their email. Once the form is submitted, it should trigger an appropriate method within theuser controller
.
I can handle the rest, I just haven't managed to connect the parts mentioned above. I have been reading railsTutorial.org and guides.rubyonrails.org but haven't been able to understand routing
form_for()
sufficiently.
User Profile Link:
<%= @user.email %> <%= link_to "(change)", email_path(@user) %>
Routes
Rails.application.routes.draw do
get 'email' => 'users#email_form'
post 'email' => 'users#changeemail'
end
User Controller
class UsersController < ApplicationController
def email_form
@user = User.find(params[:id])
end
def changeemail
@user = User.find(params[:id])
redirect_to @user
end
end
Currently the error I get once I click the link is Couldn't find User with 'id'=
which I assume means user ID is nil because I fail at passing it.
I would greatly appreciate an explanation of what data is being passed through this workflow so I can be a better developer, thank you very much!
EDIT:
The form itself:
<%= form_for(@user, url: user_path(@user)) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :new_email %>
<%= f.text_field :new_email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.submit "Submit New Email", class: "btn btn-primary" %>
<% end %>
Upvotes: 3
Views: 408
Reputation: 1555
You could do this (note :id and "as"):
Rails.application.routes.draw do
get 'email/:id' => 'users#email_form', as :email
post 'email/:id' => 'users#changeemail', as :change_email
end
The :id is then expected to be part of the route.
Alternatively, pass the id directly when generating the url:
<%= @user.email %> <%= link_to "(change)", email_path(id: @user) %>
This will make a call to "UsersController#update"
<%= form_for(@user, url: user_path(@user)) do |f| %>
...instead you would use something like::
<%= form_for(@user, url: change_email_path(@user), method: :put) do |f| %>
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for
...but in terms of best practices, if you want to do separate flow for email updating, you could be more explicit in treating it as a different resource (even though it's still the user record).
For example, you could map these to an explicit 'resource' with a #show and #update action...
Routes:
resources :user_emails, only: [:show, :update]
Controller:
class UserEmailsController < ApplicationController
def show
@user = User.find(params[:id])
end
def update
@user = User.find(params[:id])
redirect_to @user # goes back to UsersController#show
end
end
Then the route would be:
<%= @user.email %> <%= link_to "(change)", user_email_path(@user) %>
In this case we don't have to say (id: @user) since the 'resource' generates the right urls for you.
...and this would be
<%= form_for(@user, url: user_email_path(@user), method: :post) do |f| %>
Upvotes: 1