uninitialized constant ConfirmationsController error while trying to overide devise confirmations controller - ruby-on-rails-3

am trying to confirm a user account without using the built in devise confirmations controller but i happen to get the following error "uninitialized constant Confirmations Controller". Below is my confirmations controller class.
class ConfirmationsController < Devise::ConfirmationsController
def show
#user = User.find_by_confirmation_token(params[:confirmation_token])
if !#user.present?
render_with_scope :new
end
end
def confirm_account
#user = User.find(params[:user][:confirmation_token])
if #user.update_attributes(params[:user]) and #user.has_password?
#user = User.confirm_by_token(#user.confirmation_token)
flash[:notice] = "Hi " + #user.first_name + " your email has been verified. You can now start shopping and recommending other users to your supplier networks."
redirect_to #user
else
render :action => "show"
end
end
end
And in my routes.rb file i have the following:
devise_for :users, :controllers => { :confirmations => "confirmations" } do
match "confirm_account", :to => "confirmations#confirm_account"
end
And finally i have the following partial:
<p>Welcome <%= #user.first_name %>,</p><br/>
<%= form_for(resource, :url => confirm_account_path) do |f| %>
<%= f.label :email %>
<%= #user.email %>
<%= f.hidden_field :confirmation_token %>
<%= f.submit 'Confirm Account' %>
<p>Thank you for joining. Before you can purchase any item from your supplier or shared network, you will need to confirm your account first. Please follow the link below in order to confirm your account.</p>
<p><%= link_to 'Confirm my account', confirmation_url(#resource, :confirmation_token => #resource.confirmation_token) %></p><br/>
<p>Yours faithfully.</p>
<%end%>

Devise is can be easily modified for your needs. Here is a similar topic, which may be helpful for you:
Override devise registrations controller

Related

Calling two methods from one controller in nested model form

Through other posts on SO I've learned that my sign-up process using a nested model form is flawed in that I create a new User, then redirect to create its Profile. Here is the process:
user = User.new
user.email = ...
user.password = ...
user.profile = Profile.new
user.profile.first_name = ...
...
user.profile.save
user.save
It seems as if one solution is to initiate the profile method from within the UsersController create(?) action, so that I POST to both models(?) then redirect to a page with a form to fill out the rest of the profile.
But I'm not entirely sure how to do that, as I am new to programming/Rails. So can anyone give me guidance on how to introduce the Profile method within the UsersController? I gave it a go but don't think it's correct. Code for both Users/ProfilesController below:
User:
def new
#user = User.new
#user.profile = Profile.new
end
def index
#user = User.all
end
def create
#user = User.new(params[:user])
if #user.profile.save
redirect_to profile_new_path, :notice => 'User successfully added.'
else
render :action => 'new'
end
end
Profile:
def new
#user.profile = Profile.new
end
def create
#profile = Profile.new(params[:profile])
if #profile.save
redirect_to profile_path, :notice => 'User successfully added.'
else
render :action => 'new'
end
end
Routes.rb:
match '/signup' => 'profiles#new', :as => "signup"
get "signup" => "profiles#new", :as => "signup"
root :to => 'users#new'
resources :users
resources :profiles
My nested model form (the relevant parts):
<%= form_for(:user, :url => { :action => :create }, :html => {:id => 'homepage'}) do |f| %>
<%= f.text_field :email, :size=> 13, :id => "user[email]" %>
<%= f.fields_for :profile do |f| %>
<% end%>
<% end %>
If anyone could help me I'd greatly appreciate it.
You should have something like this in your models:
class User < ActiveRecord::Base
has_one :profile
accepts_nested_attributes_for :profile
end
class Profile < ActiveRecord::Base
belongs_to :user
end
...of course all backed up with proper migrations. Then while building up a form you can use fields_for helper. Here is slightly modified example from docs:
<%= form_for #user do |user_form| %>
Email: <%= user_form.text_field :email %>
<%= user_form.fields_for :profile do |profile_fields| %>
First Name: <%= profile_fields.text_field :first_name %>
<% end %>
<% end %>
And update your user and his profile in the controller in one go, thanks to accepts_nested_attributes_for :profile declaration in your model.

Rails 3 Route error - "No Route Matches"

I've been reading over this resource as well as this post to try to understand Routes more (currently learning programming/Rails by doing) but am wondering how I can fix the error I'm getting, which is No route matches {:controller=>"profiles", :action=>"show"}.
I get the error working my way through a Rails 3 sign-up process using nested model forms. The sign-up process, as follows:
user = User.new
user.email = ""
user.password = ""
user.profile = Profile.new
user.profile.save
user.save
The sign-up process starts at the homepage with the following form:
<%= form_for :user, :url => signup_path, :html => {:id => 'homepage'} do |f| %>
<div>
...
</div>
<%= f.fields_for :profile do |f| %>
<% end %>
<% end %>
Then the process goes to fill in the profile, then redirect to the new User's profile after this form is completed:
<%= form_for :profile, :html => { :multipart => true } do |f| %>
<div>
...
</div>
<%= f.fields_for :user do |f| %>
<% end %>
<% end %>
I have accepts_nested_attributes_for :user and :profile in their respective models.
My rails server it gives me a bit more detail:
ActionController::RoutingError (No route matches {:controller=>"profile.save", :action=>"show"}):
app/controllers/profiles_controller.rb:15:in `create'
So in my ProfilesController in 'create':
def create
#profile = Profile.new(params[:profile])
if #profile.save
redirect_to profile_path, :notice => 'User successfully added.'
else
render :action => 'new'
end
end
Seems clear that the issue is in profile_path, so my Routes.rb:
post "/signup" => "profiles#create", :as => "signup"
match "skip/signup", :to => "info#signupskip"
match "skip/profiles/new", :to => "profiles#newskip"
root :to => "users#create"
Can anyone help shed light on what I'm doing wrong/missing in my Routes.rb file?
The redirect path should contain the specific profile to redirect to:
if #profile.save
redirect_to profile_path(#profile), :notice => 'User successfully added.'
else
.....
Also the routes should include this line:
get "/profiles/:id" => "profiles#show", as => "profile"

Trying to create user with membership using Devise - Need help with controller

I have a standard devise installation, and I'm trying to add in functionality to add a user with a gym membership from an admin panel.
routes.rb
devise_for :users
resources :users
I am creating the user from the gym controller, so this is my gym action
def members
#gym = Gym.find(params[:id])
#user = User.new
#user.gym_users.build
#roles = Role.all
end
The gym_user is accepted in the user model
accepts_nested_attributes_for :gym_users
Then here is a portion of my form
<%= form_for #user do |f| %>
<%= f.label :email %><br />
<%= f.text_field :email %>
<% f.fields_for :gym_users do |builder| %>
<%= builder.label :item_id, "Membership Level" %><br />
<%= builder.collection_select(:item_id, #gym.membership_items, :id, :name, {:include_blank => true}) %>
<% end %>
<% end %>
What I'm having trouble with is my user controller where I actually create the user. This is the route for the membership page where the user is created
match 'gyms/:id/members' => 'gyms#members'
Finally, here's the create method on my users_controller
def create
#user = User.new(params[:user])
if #user.save
:notice => "User created successfully"
render :new
else
render :new
end
end
What I'm not sure is how to send back to that url when there is an error so that my model errors go with it, or redirect when it completes correctly.
I resolved this by making it an ajax call which eliminated the need for a redirect.

2 render templates (from devise) on one page (rails 3)

I've installed devise for my rails app, i can go to the sign in page or the sign up page. But I want them both on a welcome page...
So I've made a welcome_page_controller.rb with the following function:
class WelcomePageController < ApplicationController
def index
render :template => '/devise/sessions/new'
render :template => '/devise/registration/new'
end
end
But when i go to the welcome page i get this error:
NameError in Welcome_page#index
Showing /Users/tboeree/Dropbox/rails_projects/rebasev4/app/views/devise/sessions/new.html.erb where line #5 raised:
undefined local variable or method `resource' for #<#<Class:0x104931c>:0x102749c>
Extracted source (around line #5):
2: <% #header_title = "Login" %>
3:
4:
5: <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
6: <p><%= f.label :email %><br />
7: <%= f.email_field :email %></p>
8:
Does anybody knows a solution for this problem? Thanks in advance!
Does it have to do with the fact that it is missing the resource function? in the welcome_page controller? It's probably somewhere in the devise controller...?
Regards,
Thijs
Here's how I managed to did it.
I've put a sign up form in my home#index
My files:
view/home/index.html.erb
<%= render :file => 'registrations/new' %>
helper/home_helper.rb
module HomeHelper
def resource_name
:user
end
def resource
#resource = session[:subscription] || User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
def devise_error_messages!
return "" if resource.errors.empty?
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
sentence = I18n.t("errors.messages.not_saved",
:count => resource.errors.count,
:resource => resource_name)
html = <<-HTML
<div id="error_explanation">
<h2>#{sentence}</h2>
<ul>#{messages}</ul>
</div>
HTML
html.html_safe
end
end
You need that part because Devise works with something called resource and it should be defined so you can call your registration#new anywhere.
Like that, you should be able to register. However, I needed to display errors on the same page. Here's what I added:
layout/home.html.erb (the layout used by index view)
<% flash.each do |name, msg| %>
# New code (allow for flash elements to be arrays)
<% if msg.class == Array %>
<% msg.each do |message| %>
<%= content_tag :div, message, :id => "flash_#{name}" %>
<% end %>
<% else %>
# old code
<%= content_tag :div, msg, :id => "flash_#{name}" %>
<% end %> #don't forget the extra end
<% end %>
I found this code here
And here's something I created: I saved my resource object if invalid in a session so that the user hasn't to fill every field again. I guess a better solution exists but it works and it's enough for me ;)
controller/registration_controller.rb
def create
build_resource
if resource.save
if resource.active_for_authentication?
# We delete the session created by an incomplete subscription if it exists.
if !session[:subscription].nil?
session[:subscription] = nil
end
set_flash_message :notice, :signed_up if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => redirect_location(resource_name, resource)
else
set_flash_message :notice, :inactive_signed_up, :reason => resource.inactive_message.to_s if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords(resource)
# Solution for displaying Devise errors on the homepage found on:
# https://stackoverflow.com/questions/4101641/rails-devise-handling-devise-error-messages
flash[:notice] = flash[:notice].to_a.concat resource.errors.full_messages
# We store the invalid object in session so the user hasn't to fill every fields again.
# The session is deleted if the subscription becomes valid.
session[:subscription] = resource
redirect_to root_path #Set the path you want here
end
end
I think I didn't forget any code. Feel free to use whatever you need.
Also, you can add your sign in form in the same page (something like that:)
<%= form_for("user", :url => user_session_path) do |f| %>
<%= f.text_field :email %>
<%= f.password_field :password %>
<%= f.submit 'Sign in' %>
<%= f.check_box :remember_me %>
<%= f.label :remember_me %>
<%= link_to "Forgot your password?", new_password_path('user') %>
<% end %>
Cheers !

Rails appends id to singular route when render edit after errors

I have the following singular route:
scope '/seller' do
resource :seller_profile, :path => "/profile", :only => [:show, :edit, :update]
end
and the following controller:
class SellerProfilesController < ApplicationController
before_filter :validate_user_as_seller
def show
#seller_profile = current_user.seller_profile
end
def edit
#seller_profile = current_user.seller_profile
end
def update
#seller_profile = current_user.seller_profile
if #seller_profile.update_attributes(params[:seller_profile])
redirect_to(seller_profile_path, :notice => 'Profile was successfully updated.')
else
render :action => "edit"
end
end
end
I use a singular route given that the user must be authenticated before gaining access to the controller and therefore I can get the seller_profile from the user logged in.
This works like a charm, with only one problem. When I edit the seller_profile and validation error happen, the form is edited again and the errors are displayed correctly. The problem is that rails appends to the url the id of the edited record. For instance,
when I first edit the record, the url is:
http://0.0.0.0:3000/seller/profile/edit
but if the form is submitted with validation errors, the form itself is redisplayed under
http://0.0.0.0:3000/seller/profile.2
where 2 is the ID of the record being edited.
The form is the following:
<%= simple_form_for #seller_profile do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.submit %>
<% end %>
Everything, as said, works great but I would totally mask the ID in the url. What should I do?
I have not really worked too much with simple_form_for. But it looks like it is guessing your url always as if they were not single resources. You can provide a custom one:
<%= simple_form_for #seller_profile, :url => seller_profile_path do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.submit %>
<% end %>