I'm following Mike Hartl's Rails tutorial & ran into an issue when creating email templates. (Please note the tutorial is based on Rails 5.0.1, while I'm plowing ahead with Rails 5.1.1.)
The tutorial uses :activation_token & :activation_digest attributes to handle the security risks of signup URLs, and a :create_activation_digest hook to set their values before creating the User model.
Here's the mailer view template:
<%= link_to "Activate", edit_account_activation_url(#user.activation_token, email: #user.email) %>
The issue appears to be telling Mailer to use the value of :activation_token in the :id field of the route. (A URL definition error)
Here's the route definition, from rails routes:
edit_account_activation GET /account_activations/:id/edit(.:format) account_activations#edit
The error feedback:
No route matches {:action=>"edit", :controller=>"account_activations", :email=>"test7#example.com", :format=>nil, :id=>nil}, possible unmatched constraints: [:id]
I've tried hard-coding id: #user.activation_token in the mailer template, to no avail.
This seems like a easy one, but I'm stumped and a little worried that I'm overlooking something hidden in the transition from Rails 5.0.x to 5.1.x. Any ideas?
You are getting this error because in your config/routes.rb file, you GET /account_activations/:id/edit. That makes it necessary to send an ID which you don't want/need to do. Now I know that Rails Tutorial uses :id for token. But you're not defining id: in your link. So either you need to change the route, or change the link.
<%= link_to "Activate", edit_account_activation_url(id: #user.activation_token, email: #user.email) %>
Notice I define id:. Normally outside this tutorial though, you should consider changing your route to GET /account_activations/edit/:token and then look up the user by token.
Thanks all,
But the error was related to how I defined the :activation_token hook in the User model. All tests now pass.
Related
I'm at the point in the Hartl tutorial (chapter 11.2.1) where you create an account activation mailer and I was wondering, why are we creating an "edit" url like this:
<%= edit_account_activation_url(#user.activation_token, email: #user.email) %>
http://www.example.com/account_activations/q5lt38hQDc_959PVoo6b7A/edit
It seems like "edit" is not the right word for this. To me it would make more sense to use a method called something like "activate" instead "edit".
Why is Hartl using "edit"? I suspect it's because that is RESTful way to do it? Such as in this edit_user_url(user).
Here are the routes that the mailer is using:
resources :account_activations, only: [:edit]
Can anyone explain why he might be using "edit"?
Well practically activation of account, changes it. So from rest point of view you editing it.
If you want to be more verbose in terms of purpose, you could alias this route to activate using as method :as documentation
I have a controller Posts in which I have a method:
def report_user
...
end
I have a view where I would like a link that will perform some logic (it should NOT actually take the user to a different page, only perform the logic and possibly show a dialog box after completion). The logic is contained in the report_user action in the Posts controller:
<%= link_to "Report User", :controller => :Posts, :action => :report_user %>
I would ultimately like to pass some variables also to the report_user action, however I haven't gotten that far as I've come across this error:
No route matches {:action=>"report_user", :controller=>"Posts"}
message << " missing required keys: #{missing_keys.sort.inspect}" unless missing_keys.empty?
raise ActionController::UrlGenerationError, message
end
I'm not sure what the issue is. There is definitely an action in the Posts controller called report_user and it is not private. I'm not sure what the missing required keys means either. I've seen on SO other people with that error, but they all have routes defined that require parameters. I do not have any routes defined for this. Possibly I"m going about the entire thing in the wrong way?
As Nils suggested, you need an entry in routes.rb. Assuming that this is a member route using a GET request, that entry would look like this.
resources :posts do
get :report_user, on: :member
end
Next, you need to update your link to use the routing helpers that Rails provides.
<%= link_to "Report User", report_user_post_path(#post), remote: true %>
I included the remote: true option b/c you mentioned that clicking the link shouldn't reload the page. The default response for this request will be app/views/posts/report_user.js.erb.
I would encourage you to read up on Rails routing at http://guides.rubyonrails.org/routing.html.
I'm attempting to install Devise on a rather simple event creating/displaying Rails 4 app. I have 2 static pages and the index page displaying without authentication, and all is well there. Anything else kicks you to the "sign up" page. From there, when I attempt to create an account for myself (to simply see the other pages- simple vanilla devise installation attempt) I get a "No route matches [POST] "/registrations/user" error when clicking "submit" (f.submit)
I am using Rails 4, have the 3.0.3 version of Devise, bundled it, ran "rails generate devise:install" to install it, ran "rails generate devise user", ran db:migrate, raked the routes, and restarted the Rails server.
I even recreated the button action with the "correct" route and "get post" - no dice.
Anybody have any idea? I'm at a loss here.
Well it's always tricking debugging sever-side code without seeing it in action, but here's what should work.
yourappname/config/routes.rb :
devise_scope :user do
# matches the url '/register' to the registration controller's 'new' action and creates a :register symbol inorder to reference the link dynamically in the rest of the code
get 'register', to: 'devise/registrations#new', as: :register
end
(Assuming your register button is in your app's partial)
yourappname/app/views/layouts/application.html.erb:
<%= link_to "Register", register_path, class: "btn" %>
Now you could actually put that link_to anywhere, in any page, and it'll work. The reason for this is the 'register_path'.
When you create your route, the as: :register parameter creates a global variable that can be accessed throughout your app.
the register_path variable in your link_to method will always call the right action, even if you change your routes file.
It's just syntax. You could create any symbol you want. This would also work:
routes.rb:
# Inside get method, third parameter
as: :bowtiesarecool
someview.html.erb:
# Inside link_to method, second parameter
bowtiesarecool_path
Just match the variable name with the symbol name and a put a _path after it. The link_to method will handle everything else!
I'm using Devise and Omniauth for my login process. For some reason, I can access the route "users/auth/facebook" or "users/auth/twitter" just fine. But they don't show up when I do rake routes, so I have no idea what the helper method to get these paths is (e.g. something_something_path). Can someone help me out?
I can't show all of my routes, but I can say that the only route that matches "/users/auth/..." that's showing up is this one (from rake routes):
user_omniauth_callback /users/auth/:action/callback(.:format) {:action=>/(?!)/, :controller=>"users/omniauth_callbacks"}
BTW, when I say I "can access the route just fine", I mean this works (redirects me correctly to facebook or twitter):
<%= link_to "Connect", "users/auth/facebook" %>
Also, the routes should be the default Devise omniauth routes for the user model
With regard to why this doesn't show up in rake routes, first note how the task is implemented. It is part of railties, and it gets the routes to show as such:
Rails.application.routes.routes
So we can see that it is asking the Rails.application for its routes.
Next note that the Omniauth gem "is a flexible authentication system utilizing Rack middleware".
Because it uses Rack middleware it does not 'know' anything about the Rails.application used by rake routes, and so its routes don't appear in that task.
You can get a good introduction to Rack middleware in this Railcast.
Delving a little deeper we can see from rake middleware that OmniAuth::Builder appears before your rails app in the stack. So how does it handle the auth/twitter route?
It does so by checking for a request_path in its call, you can see the check here, and you can see how the request_path is built here (path_prefix is auth by default, and name in your case is twitter.
When using Omniauth with Devise, the path_prefix is set automatically, as noted here.
Why they dont show up on rake routes, I am not sure. But if you wanna know their alias you can find them in here: https://github.com/plataformatec/devise/wiki/OmniAuth%3A-Overview
From their docs:
Currently, Devise only allows you to make one model omniauthable.
After making a model named User omniauthable and if "devise_for
:users" was already added to your config/routes.rb, Devise will create
the following url methods:
user_omniauth_authorize_path(provider)
user_omniauth_callback_path(provider)
So if you have devise_for :model in your routes you should see that url method.
Example:
<%= link_to "Sign in with Facebook", user_omniauth_authorize_path(:facebook) %>
Also if you take a look at the implementation of devise, you can see that the URL helpers are there:
https://github.com/plataformatec/devise/blob/master/lib/devise/omniauth/url_helpers.rb
I have set up rails with devise however I can't get my authentication to work when I add the confirmable module to my application. I included the confirmable module in my User model and uncommented confirmable and the add_index confirmation token in my migration file. After rolling back the database and re-commenting these, the authentication works as specified.
I have also checked and I can't sign out of the application, even though I have provided the <%= link to "Sign Out", destroy_user_session_path %> My application gets a routing error, no route matches [GET] users/sign_out. When I run rake routes this route is available to me as
destroy_user_session DELETE /users/sign_out(.:format) {:action=>"destroy", :controller=>"devise/sessions"}
Not sure about the confirmable part, but I can tell you that the link you're using is calling a GET method. As you can see, to sign out you need a DELETE method in your link which will look like this:
<%= link_to "Sign out", destroy_user_session_path, :method => :delete %>
If you want to use GET for sign out specifically, check out the devise initializer file; somewhere at the bottom you'll see something about signing out and the default method being :delete. put this line there:
config.sign_out_via = :get
The work around that I applied is as follows: I had a conflict with the blueprint framework as it already provides an alert and notice class. If you look at devise's wiki it will have a subsection that deals with this issue. Then in order to confirm a new user, I went into the console, found the first user, and used the provided confirm! method that devise has in its documentation.