I'm using Ruby on Rails 3 with Devise and sending confirmation emails. The emails work correctly (as far as sending) but when I click on the Confirm my account link, it generates an error.
Can anyone shed some light, or at least point me in the right direction on what this is/how to fix this?
This is the error I see in the logs:
Started GET "/users/confirmation?confirmation_token=qKvZWHgj6ncYAyuQq3e1" for 127.0.0.1 at 2012-08-15 20:57:11 +0300
Processing by ConfirmationsController#show as HTML
Parameters: {"confirmation_token"=>"qKvZWHgj6ncYAyuQq3e1"}
User Load (9.0ms) SELECT "users".* FROM "users" WHERE "users"."confirmation_token" = 'qKvZWHgj6ncYAyuQq3e1' LIMIT 1
Completed 500 Internal Server Error in 35920ms
NoMethodError (undefined method `only_if_unconfirmed' for #):
app/controllers/confirmations_controller.rb:58:in `with_unconfirmed_confirmable'
app/controllers/confirmations_controller.rb:40:in `show'
Rendered C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/actionpack-3.2.5/lib/action_dispatch/middleware/templates/rescues/_trace.erb (8.0ms)
Rendered C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/actionpack-3.2.5/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (3.0ms)
Rendered C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/actionpack-3.2.5/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (4479.3ms)
I verified that the token in the url is an exact match for this user in the db.
Probably you have a really recent version of devise, and it changed the way the confirmation token is handled, so if you generate the views with devise like so:
rails g devise:views
Then under the app/views/devise/mailer/confirmation_instructions.html.erb file you have something like:
....
<%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #resource.confirmation_token) %>
....
You should change that for:
<%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #token) %>
As you can see they use an instance variable called #token instead of #resource.confirmation_token
That should do the trick!
Related
I'm following Michael Hartl tutorial about Rails 5 ActionCable, to build a simple chat, and a problem is occurring inside my create action in MessageController:
def create
message = current_user.messages.build(message_params)
if message.save
ActionCable.server.broadcast 'room_channel',
content: message.content,
username: message.user.username
head :ok
end
end
It goes until head :ok, and after that, display an empty HTML page. The log is:
Processing by MessagesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"h9UsB78aX8mO8Nyn8eZEUuDzAOxL4V7UCMwNuTfwALliMv7OCkcUIeR4/xXIcvPjwq9H1bphjn6G96G+0VYisw==", "message"=>{"content"=>"oi"}, "commit"=>"Send"}
User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Message Load (2.1ms) SELECT "messages".* FROM "messages" ORDER BY "messages"."created_at" DESC LIMIT ? [["LIMIT", 50]]
(0.3ms) begin transaction
SQL (9.3ms) INSERT INTO "messages" ("content", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["content", "oi"], ["user_id", 1], ["created_at", 2016-09-19 02:12:58 UTC], ["updated_at", 2016-09-19 02:12:58 UTC]]
(9.1ms) commit transaction
[ActionCable] Broadcasting to room_channel: {:content=>"oi", :username=>"alice"}
Completed 200 OK in 69ms (ActiveRecord: 22.0ms)
RoomChannel transmitting {"content"=>"oi", "username"=>"alice"} (via streamed from room_channel)
Finished "/cable/" [WebSocket] for 10.0.2.2 at 2016-09-19 02:12:58 +0000
RoomChannel stopped streaming from room_channel
(After that, I can refresh the page and the message is displayed properly)
Why that is happening?
My RoomChanel class:
class RoomChannel < ApplicationCable::Channel
def subscribed
stream_from "room_channel"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end
My room.coffee
App.room = App.cable.subscriptions.create "RoomChannel",
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
alert data.content
I know the answer is accepted already, but this solution worked for me without having to remove head :ok, maybe it helps somebody out.
Normally in the development environment people are running localhost:3000 but i was running on a different port, localhost:3030.
And this case i had to add an allowed request origin for that port, like so:
config.action_cable.allowed_request_origins = [
'http://localhost:3030'
]
to my /config/environments/development.rb
Following a sugestion, I'm adding as answer what I did to get around this problem. It doesn't answer why that happens, but solve the problem.
The solution is: remove head :ok.
Aparently it's unecessary, because if I add a test whit assert_response :success to the action, it'll pass.
I'm following Michael's tutorial for ActionCable and had the same problem.
I think this was due to the format of the form partial _anything.html.erb.
app/views/messages/_message_form.html
As you go through the tutorial, you're upgrading to Action Cable features. But in the _message_form partial, it is still with the usual HTTP request. So after you broadcast a message using the messages_controller.rb, the browser render an empty page because the form was already rendered.
app/views/messages/_message_form.html, Originally:
<div class="message-input">
<%= form_for(#message) do |f| %>
<%= f.text_area :content %>
<%= f.submit "Send" %>
<% end %>
</div>
So, you have to add the remote: true to the form, like this:
<div class="message-input">
<%= form_for(#message, remote: true) do |f| %>
<%= f.text_area :content %>
<%= f.submit "Send" %>
<% end %>
</div>
Adding the remote: true makes an JS request (Ajax, in this case)
Quoting Michael:
You can verify by submitting a message that it appears as desired, but in
fact this is a cheat because the form from Listing 6 is currently submitting
an ordinary HTTP POST request, which causes the page to refresh. In order
to use Action Cable, we need to change the form to submit a remote request
that submits an Ajax request without refreshing the page. We can do this by
including the remote: true option in the call to form_for.
Note that I'm doing everything in localhost:3000
I am using devise_invitable to create guest accounts to access a document. When accessing a document, a guest can click on an upgrade button that will upgrade to a full account. Clicking on the upgrade button is accepting devise_invitable invitation.
Was previously working: no longer working.
Environment:
rails 4.2.3 (recently upgraded)
devise 3.4.1
devise_invitable 1.3.6
I use a header partial for a guest user that generates an upgrade link:
<% #invite_link = accept_user_invitation_url(invitation_token: #invite_token) %>
<%= link_to "Upgrade", #invite_link, class: "btn btn-danger btn-lg" %>
#invite_token is created like:
user = current_user
user.invite! do |u|
u.skip_invitation = true
end
#invite_token = user.raw_invitation_token
So link_to helper generates something like: https://myapp/users/invitation/accept?invitation_token=vv_JqeFDLfyX65tx2KhR
Except when I click on the link, it takes me to: https://myapp/users/sign_in
With error message: The invitation token provided is not valid!
Log reports something like:
Started GET "/users/invitation/accept?invitation_token=vv_JqeFDLfyX65tx2KhR" for 31.15.32.222 at 2015-10-15 19:18:34 +1100
Processing by Devise::InvitationsController#edit as HTML
Parameters: {"invitation_token"=>"vv_JqeFDLfyX65tx2KhR"}
User Load (5.9ms) SELECT "users".* FROM "users" WHERE "users"."invitation_token" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["invitation_token", "ea9be9890c684e13ece13ec02f89bade81fcd3ac1fb982db72d8f8561d0cf289"]]
Redirected to https://myapp/
Filter chain halted as :resource_from_invitation_token rendered or redirected
Completed 302 Found in 53ms (ActiveRecord: 5.9ms)
Started GET "/" for 31.15.32.222 at 2015-10-15 19:49:52 +1100
Processing by PagesController#index as HTML
Redirected to https://myapp/users/sign_in
Completed 302 Found in 11ms (ActiveRecord: 0.0ms)
Am able to make this work via rails console.
If I run rails console in parallel, I am able to step through the above steps and generate an accept_invitation link that works as expected (i.e. it prompts user to set a password for the full account).
NB: the raw_invitation_token is different in the rails console session.
What am I missing?
I found code that called user.invite! to generate raw_invitation_token when page was displayed and after the accept_invitation link was generated. This meant that the token in the accept_invitation link was now outdated.
Going via the console, this code was not called as no controller, view or javascript components are invoked. So when using the console, things worked as expected.
Fixed and all back to normal.
I added a new migration to a table in my app and I migrate. Since it had errors, I dropped and migrated it. When I signed up for a user and tried to confirm it using email(devise,confirmable) it just won't confirm. It says invalid confirmation token. I have tried restarting the server. Dropping and migrating again, everything possible as far as I know. I am using Rails 3.2.9 and Ruby 1.9.3. Devise version is 3.1.0. Devise is also included in other gems I have added like rails-messaging and active-admin.
Started POST "/users/confirmation" for 127.0.0.1 at 2013-09-16 19:42:47 +0530
Processing by Devise::ConfirmationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"4lMxdlsMqRCJB1doxt/hTCQhUPvAoGPiSbr9wQA/ZAQ=", "user"=>{"email"=>"pro.aravind#gmail.com"}, "commit"=>"Resend confirmation instructions"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."unconfirmed_email" = 'pro.aravind#gmail.com' LIMIT 1
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."email" = 'pro.aravind#gmail.com' LIMIT 1
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."confirmation_token" = 'cc47150f51ec476aa40ea1d546e27c0dafc37ffc8bb82272a9f2377c863daed1' LIMIT 1
(0.1ms) begin transaction
(0.3ms) UPDATE "users" SET "confirmation_token"='cc47150f51ec476aa40ea1d546e27c0dafc37ffc8bb82272a9f2377c863daed1', "confirmation_sent_at" = '2013-09-16 14:12:47.174313', "updated_at" = '2013-09-16 14:12:47.175384' WHERE "users"."id" = 1
(175.3ms) commit transaction
Rendered devise/mailer/confirmation_instructions.html.erb (0.6ms)
Sent mail to pro.aravind#gmail.com (5099ms)
Date: Mon, 16 Sep 2013 19:42:47 +0530
From: please-change-me-at-config-initializers-devise#example.com
Reply-To: please-change-me-at-config-initializers-devise#example.com
To: pro.aravind#gmail.com
Message-ID: <523711df6bb56_3a029657f88282b#aravind-VPCEB46FGB.mail>
Subject: Confirmation instructions
Mime-Version: 1.0
Content-Type: text/html;
charset=UTF-8
Content-Transfer-Encoding: 7bit
<p>Welcome pro.aravind#gmail.com!</p>
<p>You can confirm your account email through the link below:</p>
<p>Confirm my account</p>
Redirected to http://localhost:3000/users/sign_in
Completed 302 Found in 5387ms (ActiveRecord: 0.0ms)
Going to add my experience here in case it can help someone else. The upgrade to Device 3.1 as BillyMFH said changed the way tokens are created. The blog post has a lot of information in it, and the solution to the problem in this answer is a temporary one.
If config.allow_insecure_token_lookup is set to false (and once this option is deprecated), the fix in my case was to update the email views Devise uses to send out links containing tokens.
Old Devise email views contain lines like this:
<p><%= link_to 'Change my password', edit_password_url(#resource, :reset_password_token => #resource.reset_password_token) %></p>
This uses the old token stored in the DB. Now you simply do this:
<p><%= link_to 'Change my password', edit_password_url(#resource, :reset_password_token => #token) %></p>
Just replace the old token from resource with the new instance variable #token
The link in the blog post to this change is highlighted here: Devise email view token change
This likely has to do with the security updates in Devise 3.1. The token that is sent to the user does not match the one that is in the database. You could turn off this feature by including this in your devise initializer:
config.allow_insecure_token_lookup = true
But it would be best to just delete the user and create a new one with the new token system.
See this blog post about the security changes in Devise 3.1: http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/ You're
looking for the section titled "Store digested tokens in the database"
Just you need to make the following changes while you update devise or else
In following line in file app/views/devise/mailer/confirmation_instructions.html.erb
<p><%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #resource.confirmation_token) %></p>
with new line as -
<p><%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #token) %></p>
This will definitely solve your problem, it just work for me.
Cheers!
I am developing a rails application which should send push notifications to iOS devices. I am using apn_on_rails gem. Everything works fine in the rails console. However when I run the server, I get undefined method errors for all the basic view methods such as content_for or form_tag etc:
When I take require 'apn_on_rails' from my development.rb out, the views work again, but of course without push notifications.
Here is an example trace:
Processing DashboardController#index (for 127.0.0.1 at 2011-02-27 13:55:59) [GET]
User Load (0.2ms) SELECT * FROM "users" WHERE ("users"."id" = 1)
CACHE (0.0ms) SELECT * FROM "users" WHERE ("users"."id" = 1)
Rendering template within layouts/dashboard
Rendering dashboard/index
ActionView::TemplateError (undefined method `content_for' for #<ActionView::Base:0x103343970>) on line #1 of app/views/dashboard/index.html.erb:
1: <% content_for :header do %>
2: <%= render :partial => "header", :locals => {:title => "Dashboard"} %>
3: <% end %>
app/views/dashboard/index.html.erb:1
app/controllers/dashboard_controller.rb:6:in `index'
Rendered rescues/_trace (28.5ms)
Processing ApplicationController#index (for 127.0.0.1 at 2011-02-27 13:55:59) [GET]
ActionView::TemplateError (undefined method `debug' for #<ActionView::Base:0x103343970>) in /Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/templates/rescues/_request_and_response.erb:
Rendered rescues/_trace (24.0ms)
/!\ FAILSAFE /!\ Sun Feb 27 13:55:59 +0100 2011
Status: 500 Internal Server Error
ActionView::TemplateError (undefined method `debug' for #<ActionView::Base:0x1031eaad8>) in /Library/Ruby/Gems/1.8/gems/actionpack-2.3.8/lib/action_controller/templates/rescues/_request_and_response.erb:
In /library/ruby/gems/1.8/gems/actionpack-2.3.8/lib/action_controller/templates/rescues/_request_and_response.erb
Thanks for any help...
It is not evident whether you call config.gem 'apn_on_rails' - it sounds more like you are require:ing the library, which probably is something you should not do at this point: the point of environment setup.
Have the config.gem things in your environment setup (i.e. development.rb), but make eventual requires happen later (->in the controller / model / helper in question).
I am successfully using Authlogic and I am trying to add the ability for users to reset their password by using this tutorial. When I submit the request (to the PasswordResetsController#create action) to reset the password I am getting this error:
TypeError (can't convert nil into String):
app/models/user.rb:19:in `deliver_password_reset_instructions!'
app/controllers/password_resets_controller.rb:12:in `create'
I have been through tutorial several times and also combed through the sample app of it here. I can't seem to figure out what is going on. Anyone have any experience/direction on this implementation and error?
Here is the full terminal output:
Processing PasswordResetsController#create (for 127.0.0.1 at 2010-11-11 11:32:19) [POST]
Parameters: {"commit"=>"Reset my password", "authenticity_token"=>"G2dtgfJJktJN7iX1FWPHvG5wjLKkIXEIZvJ72+zfSIk=", "email"=>"bgadoci#gmail.com"}
User Load (0.4ms) SELECT * FROM "users" WHERE ("users"."email" = 'bgadoci#gmail.com') LIMIT 1
User Update (0.3ms) UPDATE "users" SET "updated_at" = '2010-11-11 17:32:19', "perishable_token" = 'uu_LhCF77GCNbzYfHb2v' WHERE "id" = 1
TypeError (can't convert nil into String):
app/models/user.rb:19:in `deliver_password_reset_instructions!'
app/controllers/password_resets_controller.rb:12:in `create'
Rendered rescues/_trace (129.1ms)
Rendered rescues/_request_and_response (0.3ms)
Rendering rescues/layout (internal_server_error)
User.rb
def deliver_password_reset_instructions!
reset_perishable_token!
Notifier.deliver_password_reset_instructions(self)
end
Update:
I'm using rails 2.3.8 and ruby 1.8.7
Update:
Notifier.rb
default_url_options[:host] = "foobar.com"
def password_reset_instructions(user)
subject "Password Reset Instructions"
from "foobar"
recipients user.email
sent_on Time.now
body :edit_password_reset_url => edit_password_reset_url(user.perishable_token)
end
Update:
Here is the /views/notifier/password_rest_instruction.erb
A request to reset your password has been made. If you did not make this request, simply ignore this email. If you did make this request just click the link below:
<%= #edit_password_reset_url %>
If the above URL does not work try copying and pasting it into your browser. If you continue to have problem please feel free to contact us.
The output is telling you there's an error in line 19 of User#deliver_password_reset_instructions! Paste your code and I'll be able to help you more...