I have a Rails 4.1.6 application and use Devise for the 'user' model. The link to my sign in page works fine:
<%= link_to 'Sign in'.upcase, new_user_session_path %>
results in
SIGN IN
However, adding a link to an action on another controller breaks the link to sign_in:
<%= link_to( 'GET STARTED', {controller: :contacts, action: :new}, method: :get) %>
<%= link_to 'Sign in'.upcase, new_user_session_path %>
still produces the same HTML:
<a data-method="get" href="/contacts/new">GET STARTED</a>
SIGN IN
But, the 'SIGN IN' link no longer works, with this error:
ActionController::UrlGenerationError at /users/sign_in
No route matches {:action=>"new", :controller=>"devise/contacts"}
This answer is for a similar situation and tells me that 'Rails is looking for a partial scoped under Devise since this is the one under which you're rendering.' But, my scope understanding is weak and I'm still struggling with how to fix this.
# relevant portion of routes.rb:
devise_for :users, :controllers => { registrations: 'registrations' }
resources :users
match '/contacts/new', to: 'contacts#new', via: 'get'
I'm not 100% sure why this is happening, but I would suggest dropping method: :get from your link. I'd also suggest using the contacts_new_path helper instead of using { controller: ..., action: ... }. Finally, you can define your route using the more standard resource :contacts, only: :new (which will change the method to new_contact_path).
So, routes.rb
resource :contacts, only: :new
In your_template.html.erb
<%= link_to 'GET STARTED', new_contact_path %>
<%= link_to 'Sign in'.upcase, new_user_session_path %>
Related
I am trying to add voting to my site. I have improvements that are created and displayed inside of the projects show page. I'm trying to allow users to vote on improvements but I am getting an error that I think is related to how I'm linking the like button.
in my routes.rb file:
resources :projects do
resources :improvements do
member do
put "like" => "improvements#upvote"
put "unlike" => "improvements#downvote"
end
end
end
In my view:
<%= link_to like_improvement_path(improvement), class: "like", method: :put do %>
Rails recommended me to write:
<%= link_to project_like_improvement_path(improvement), class: "like", method: :put do %>
But this doesn't work. So I tried doing this in my routes.rb:
resources :projects do
resources :improvements
end
resources :improvements do
member do
put "like" => "improvements#upvote"
put "unlike" => "improvements#downvote"
end
end
Using the original link_to, the voting works, but clicking on the vote button takes me to the improvements show page. I want to stay on the projects page.
If:
<%= link_to like_improvement_path(improvement), class: "like", method: :put do %>
Works then in the improvements controller's (upvote?) action simply do a:
redirect_to projects_path
At the end of whatever else you do model wise.
Change "projects_path" to the correct route for the page.
I had the same problem. The solution with your original routes.rb:
<%= link_to like_project_improvement_path(improvement.project, improvement), class: "like", method: :put do %>
You can write a redirect_to inside the upvote and downvote methods in the improvements controller.
I am trying to learn Ruby on Rails. I have followed youtube tutorial to create simple authentication in ruby. Everything is working fine but I cant understand it.
I have routes
resources :sessions, only: [:new, :create, :destroy]
get 'signup', to: 'users#new', as: 'signup'
get 'login', to: 'sessions#new', as: 'login'
get 'logout', to: 'sessions#destroy', as: 'logout'
I have controllers for sessions and users
sessions_controller
def new
end
def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_url, notice: 'Logged in !'
else
render :new
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: 'Logged out!'
end
and my views/sessions/new.html.erb
<h1>Log In</h1>
<%= form_tag sessions_path do %>
<div class="field">
<%= label_tag :email %><br>
<%= text_field_tag :email %>
</div>
<div class="field">
<%= label_tag :password %><br>
<%= password_field_tag :password %>
</div>
<div class="actions">
<%= submit_tag "Log In" %>
</div>
<% end %>
I want to understand how my login form works . I understand that when i go to /login it will request action from session controller and method new, but how it knows when i type my email and password and press submit what to do next ? In php there is . How it works in ruby ?
That's a pretty broad question, but I will try to explain some of the rails-magic you probably want to know.
First, you should take a closer look at the viewhelper docs, especially form_tag. It will create a form html tag with the sessions_path as first argument and the do-block as the second.
sessions_path is a view helper, provided by rails because you used
resources :sessions, only: [:new, :create, :destroy]
in your routes. It returns a string that should look like this "/sessions". You should take a look at this guide to understand rails routing better.
<%= form_tag sessions_path do %>
...
<% end %>
is the same as
<form action="/sessions" method="post">
...
</form>
So, the submit is nothing more than a regular html form submit to "/sessions". Rails will map a post request to "/sessions" to the SessionsController#create method, where we authenticate the user by email and password and set the id in the session cookie
if user && user.authenticate(params[:password])
session[:user_id] = user.id
# ...
In addition to Ninigi's good answer I just wanted to add that ...
resources :sessions, only: [:new, :create, :destroy]
will generate routes which you can view by using rake routes in the terminal.
Also form_tag etc are just view helpers that will generate html, simply use inspect element in your browser to see what it has done.
I would have added this as a comment but I don't have enough reputation yet.
A very good starting point for understanding this will be the book Ruby on Rails Tutorial by Michael Hartl. Its available free to read online.
See chapter 7 onwards for login/signup etc.
The step by step explanations are very useful.
The link : https://www.railstutorial.org/book
and welcome to RoR
I'm following this answer on how to clone a record.
I can't though workout how to phrase the link and route it.
It is in my #miniature show view so I thought it should be something like
<%= link_to 'clone', :controller => :miniatures_controller, :action => :clone %>
and the route
match 'clone', to: 'miniatures#clone', via: 'get'
but this is clearly wrong. I am using #miniature in place of the above answer's #prescription.
What if you just use clone_path:
<%= link_to 'clone', clone_path %>
Cause rake routes shows just clone route. It works with the same routes.
If you are not satisfied with route and you should pass parameters (like miniature_id), add member to your resource (probably nested), like:
resources :miniatures do
member do
get 'clone'
end
end
This will be clone_miniature_path where you should pass #miniature:
<%= link_to 'clone', clone_miniature_path(#miniature) %>
I was trying to rename all the registrations routes provided by Devise, but now I can't update the account info anymore. It renders registrations#edit action via GET request with no problems, but the PUT and DELETE requests all goes to the sign_up path somehow.
Here's my current routes file:
...
devise_for :users, path: '', path_names: { sign_in: 'login', sign_out: 'logout', sign_up: 'signup' }, controllers: { registrations: "registrations" }, skip: [:registrations]
as :user do
get '/admin/cancel' => 'registrations#cancel', as: :cancel_user_registration
post '/signup' => 'registrations#create', as: :user_registration
get '/signup' => 'registrations#new', as: :new_user_registration
get '/admin/settings/account' => 'registrations#edit', as: :edit_user_registration
put '/admin/settings/account' => 'registrations#update', as: :update_user_registration
delete '/admin/settings/account' => 'registrations#destroy', as: :destroy_user_registration
end
Now when I visit "/admin/settings/account", it renders the edit account view as expected. But the "Update" button points to "/signup" with method PUT, and the "Cancel my account" link also points to "/signup" but with method DELETE.
Then I digged into the view for rendering "registrations/edit", and found these
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> ...
... <%= link_to "Cancel my account", registration_path(resource_name), confirm: "Are you sure?", method: :delete %> ...
So registration_path(resource_name) is actually in charge of generating the correct routes for PUT and DELETE. But since I changed the default Devise registrations routes, it can no longer recognize and spit out the correct paths.
Does anyone know how I can fix this? What does registration_path(resource_name) actually mean?
You should change your form paths to the paths you created. Like this:
<%= simple_form_for(resource, as: resource_name, url: update_user_registration_path, html: { method: :put }) do |f| %>
<%= link_to "Cancel my account", destroy_user_registration_path, confirm: "Are you sure?", method: :delete %>
When I was writing my answer I tried googling for the source code so I could show you but I couldn't find it. Anyway, registration_path receives an argument which is the name of the model you want to create, update or destroy and then returns the appropriate url to make the call. So imagine you have 2 roles or models: User and Admin. Now, using the same code, you can destroy both using that path. <%= link_to "Cancel my account", registration_path(resource_name), method: :delete %> returns /users/cancel for a user and returns /admins/cancel for an admin.
In your routes.rb file, you are defining the names of routes for a certain model, right? That's what you are doing with the line as :user do. You are defining the names of routes for a User. So let's continue with an example of cancelling an account. With this:
as :user do
delete 'delete_account' => 'registrations#destroy', as: :destroy_user_registration
end
You can use the destroy_user_registration_path without passing resource_name because devise already knows that this url is related to the User model.
EDIT: Even if you had more than one model, you could change registration_path(resource_name) to update_user_registration_path in your view. Remember, all these methods do is create a url to which you submit the form, that's all.
The only thing you have to be careful about is editing your routes file.
I am using devise for authentication on my project. I created a basic controller called panel with rails. When I am at the home url the link works as it should. But for some reason the link_to in my layout file attempts to find a route that does not exist when I go to /users/sign_in, the default login for devise.
In my layout file I have this link that should always be shown.
<%= link_to "Panel", :controller => "panel", :action => "index" %>
when I attempt to access the default user login path on devise /users/sign_in it gives the error: ActionController::RoutingError in Devise/sessions#new
No route matches {:controller=>"devise/panel"} from the layout file.
routes:
get "panel/index"
get "home/index"
devise_for :users
It looks like the routes go into some sort of devise scope when I click on the link for the users/sign_in path.
Try this:
routes.rb:
get "panel/index" => 'panel#index', :as => 'panel'
In your controller:
<%= link_to "Panel", panel_path %>
get "panel/index", :as => :panel_index
<%= link_to "Panel", panel_index_path %> |
Doing the following also solves it,
<%= link_to "Panel", :controller => "/panel", :action => "index" %>
Source: https://github.com/plataformatec/devise/issues/471