How to add new action into Devise registrations controller? - ruby-on-rails

I know how to override default controllers and it is working, but now I need to add new action into Registrations controller.
I need to update user fields. I need to add First and Last name in this form, but I don't want to use standard edit page, because it will be separate page.
So I need other page. I have paypal..html.erb in my registrations folder, but I can't render it from action in regustrations controller.
Paypal action:
class RegistrationsController < Devise::RegistrationsController
def paypal
end
...
end
routes.rb:
devise_for :users, :controllers => {:registrations => 'registrations', :sessions => 'sessions'} do
match 'paypal' => 'registrations#paypal'
end
but somehow it render new registration file. Here is error:
NoMethodError in Registrations#paypal
Showing C:/1508/app/views/devise/registrations/new.html.erb where line #22 raised:
How I can use update form to do this and what I'm doing wrong ?

I added this to my routes to make it work
devise_scope :user do
get 'paypal(/:id)', :action => 'paypal', :controller => 'user/registrations', :as => 'paypal'
end

Your question seems a little unclear, however Why not explicitly render the view?
def paypal
render 'devise/registrations/paypal'
end
If you have multiple type of users it may be better to separate out the paths and routing.
https://github.com/plataformatec/devise/wiki/How-To%3a-Customize-routes-to-user-registration-pages

Related

Devise NoMethodError in Devise::Sessions#create

I have a small problem that I cant track down. Basically I have my application controller and in my application controller I have a method:
def getCategories
#categories = Category.all
end
Nothing special I have a sidebar partial view that I load in to my main layout. This partial is loaded by almost all controllers/actions with few exceptions so to avoid always declaring this method i simply have a before_filter to invoke this method so that #categories are automatically included in all controllers.
The problem now is when I attempt to login using devise sign in view it tries to redirect me to root however for some reason the #categories are not included and in turn throw this exception:
NoMethodError in Devise::Sessions#create
Which is confusing because according to devise documentation if you set root :to => 'home#index' as in my case after processing user login user should be redirected to root which points to home controller which should due to before_filter include the #categoires variable.
What am I doing wrong here ?
Maybe you can try adding a new controller "Registrations" and add your method:
class RegistrationsController < Devise::RegistrationsController
def getCategories
#categories = Category.all
end
end
then Modify config/routes.rb to use the new controller
Modify your devise_for line in routes.rb to look like the below.
devise_for :users, :controllers => { :registrations => "registrations" }
replace root :to => 'home#index' with
devise_scope :user do
match "/", to: "devise/registrations#new", via: 'get'
end

Devise redirect to custom action on sign in

I'm using Devise for user authentication, and want to have the user redirected to a custom action that I have set up for the User class called 'myaccount'. However, I can't get the syntax right - I'm getting varying errors with everything I'm trying.
This code might show you what I'm trying to acheive (it doesn't work though):
def after_sign_in_path_for(resource)
redirect_to :controller => 'users', :action => 'myaccount', :id => current_user.id and return
end
And the routes:
devise_for :users, :controllers => { :registrations => "registrations" }
devise_for :users
resources :users do
member do
get 'myaccount'
end
end
Apologies, it's probably quite a newbie question - but how do I either change my redirect, or add a new route so that e.g. user_sign_in_path would work?
Thanks!
UPDATE:
In case anyone else finds this question, this is what worked for me:
url_for :controller => '/users', :id => current_user.id, :action => 'myaccount'
which is the correct order that I need it in. I had to put a slash infront of the controller name to make it use that instead of the Devise controller.
you don't have to call redirect_to
def after_sign_in_path_for(resource)
{ controller: 'users', action: 'myaccount', id: current_user.id }
end
if that doesn't work, wrap that up in url_for and that should work :)

Devise routes /:param not working

Using devise 2.1.0
I am trying to send the new registration page a PricingPlan model.
So in my routes I have:
devise_scope :user do
delete "/logout" => "devise/sessions#destroy"
get "/login" => "devise/sessions#new"
get "/signup/:plan" => "devise/registrations#new"
end
And I override the devise registration controller. With this in my routes.rb to make it work:
devise_for :users, :controllers => {:registrations => "registrations"}
In my actual Registration controller which overrides Devise's controller I have:
class RegistrationsController < Devise::RegistrationsController
view_paths = "app/views/devise"
def new
super
#plan = PricingPlan.find_by_name(params[:plan])
end
So that the default views still go to devise....
In my new view for the registration controller I call this:
<h3>You've chosen the <%= #plan.name %> plan.</h3>
And I get this error:
undefined method `name' for nil:NilClass
Also... in my PricingPlan model:
class PricingPlan < ActiveRecord::Base
has_many :users
And in my User model:
class User < ActiveRecord::Base
belongs_to :pricing_plan
I'm rather new at rails.
For some reason your #plan is empty...
try changing the line below just to make sure that you are finding a plan...
#plan = PricingPlan.find_by_id(1)
if so, you are probabl trying to find by the wrong argument... do you have a column "plan" in your database?
#plan = PricingPlan.find_by_name(params[:______])
When I did a raise in my registration controller, I realize that when I was hitting /signup/:plan it wasn't hitting the registrations controller that I had overode from devises registration controller.
I figure out the reason:
Because I had made my own controller, the scope is no longer devises scope any more... So this was WRONG:
get "/signup/:plan" => "devise/registrations#new"
This however is CORRECT:
get "/signup/:plan" => "registrations#new"
So that part of my routes looks like this:
devise_scope :user do
delete "/logout" => "devise/sessions#destroy"
get "/login" => "devise/sessions#new"
get "/signup/:plan" => "registrations#new"
end
Everything else in the code stayed the same.
Thanks for #gabrielhilal for making me trace out the controller.

How do I add a route which maps to a slug url generated by the stringex gem in ruby on rails 3.1?

It seems simple, in my model I have:
class CustomerAccount < ActiveRecord::Base
acts_as_url :name
def to_param
url # or whatever you set :url_attribute to
end
end
And in my controller, I have:
class CustomerAccountsController < ApplicationController
def show # dashboard for account, set as current account
#account = CustomerAccount.find_by_url params[:id]
no_permission_redirect if !#account.has_valid_user?(current_user)
set_current_account(#account)
#latest_contacts = Contact.latest_contacts(current_account)
end
end
What's currently in the routes.rb is:
resources :customer_accounts, :path => :customer_accounts.url do
member do
get 'disabled'
post 'update_billing'
end
end
That gives me the following error when I try to generate data via rake db:seed, or at least I assume the entry in routes is what's doing it.
undefined method `url' for :customer_accounts:Symbol
So what do I need to do to get the route set up? What I'd like is http://0.0.0.0/customeraccountname to map to the view for the customer account page.
UPDATE:
Here is the code that ended up working in routes.rb, which I discovered after looking at the examples in the answer below:
resources :customer_accounts, :path => '/:id' do
root :action => "show"
member do
get 'disabled'
post 'update_billing'
end
end
If you want to set it up so you have a route like you show, do this:
get '/:id', :to => "customer_accounts#show"
If you want the disabled and update_billing actions underneath this:
get '/:id/disabled', :to => "customer_accounts#disabled"
post '/:id/update_billing', :to => "customer_accounts#update_billing"
Alternatively (and much neater):
scope '/:id' do
controller "customer_accounts" do
root :action => "show"
get 'disabled'
get 'update_billing'
end
end

How to add a custom RESTful route to a Rails app?

I'm reading these two pages
resources
Adding more RESTful actions
The Rails Guides page shows
map.resources :photos, :new => { :upload => :post }
And its corresponding URL
/photos/upload
This looks wonderful.
My routes.rb shows this
map.resources :users, :new => { :signup => :get, :register => :post }
When I do: [~/my_app]$ rake routes
I see the two new routes added
signup_new_user GET /users/new/signup(.:format)
register_new_user POST /users/new/register(.:format)
Note the inclusion of /new! I don't want that. I just want /users/signup and /users/register (as described in the Rails Routing Guide).
Any help?
When you expose a controller as a resource, following actions are automatically added:
show
index
new
create
edit
update
destroy
These actions can be categorized in to two groups:
:member actions
The URL for the member action has the id of the target resource. E.g:
users/1/edit
users/1
You can think of :member action as an instance method on a class. It always applies on an existing resource.
Default member actions: show, edit, update, destroy
:collection actions
The URL for the :collection action does not contain the id of the target resource. E.g:
users/login
users/register
You can think of :collection action as a static method on a class.
Default collection actions: index, new, create
In your case you need two new actions for registration. These actions belong to :collection type( as you do not have the id of the user while submitting these actions). Your route can be as follows:
map.resources :users, :collection => { :signup => :get, :register => :post }
The URL for the actions are as follows:
users/signup
users/register
If you want to remove a standard action generated by Rails use :except/:only options:
map.resources :foo, :only => :show
map.resources :foo, :except => [:destroy, :show]
Edit 1
I usually treat the confirmation action as a :member action. In this case params[id] will contain the confirmation code.
Route configuration:
map.resources :users, :member => { :confirm => :get}
URL
/users/xab3454a/confirm
confirm_user_path(:id => #user.confirmation_code) # returns the URL above
Controller
class UsersController < ApplicationController
def confirm
# assuming you have an attribute called `confirmation_code` in `users` table
# and you have added a uniq index on the column!!
if User.find_by_confirmation_code(params[id])
# success
else
# error
end
end
end
This can be taken as just another syntax -- something good to know may be.
Syntax 1:
resources :users do
member do
get 'signup'
post 'register'
end
end
Rake Route Output will include
signup_users GET /users/signup(.:format) {:action=>"signup", :controller=>"users"}
register_users POST /users/register(.:format) {:action=>"register", :controller=>"use
rs"}
Syntax 2:
If you have only one collection route
resources :users do
get 'signup', :on => :collection
end
If i'm understanding your question right, you just want to rename the urls of the new and create actions.
This would be done like so:
map.resources :users, :path_names => {:new => 'signup', :create => 'register'}
If you really would like to add new routes with corresponding controller actions, then Damiens answer is the way to go.
The new option allows you to create new routes for creating new objects. That's why they're prefixed with that term.
What you're looking for is the :collection option.
map.resources :users, :collection => { :signup => :get, :register => :post }
Which will create the /users/signup and /users/register urls.

Resources