rails 3.1, why I can't override 'create' at Devise::SessionsController? - devise

I have devise 1.4.8, and I am trying to override create at Devise::SessionsController to execute some logic once user signed in.
Here is my class: (stored at \app\controllers\students\sessions_controller.rb)
class Students::SessionsController < Devise::SessionsController
def create
super
end
end
here is my routes.rb
devise_for :students, :controllers => { :sessions => "students/sessions" }
but, overridden create is never called! instead, only the create at super class is called
any idea ?

it was a problem in the routes.rb,
I have this line, and it worked:
devise_for :students do post '/students/sign_in' => 'students/sessions#create' end
but, I've deleted all lines for :students at routes.rb

Related

Issue with helper_methods from views rails

I have a very frustrating issue.
I can't call any helper method from my views in rails.This is what I have:
ApplicationController.rb
class ApplicationController < ActionController::Base
protect_from_forgery
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
helper_method :all
end
/app/views/welcome/_navi_bar.haml:
%ul.nav.nav-pills.pull-right
%li.pull-right
- if current_user
%a.btn-small{"data-toggle" => "modal", :href => log_out_path, :role => "button"}
%i.icon-user.icon-white
%strong
Log Out
- else
%a.btn-small{"data-toggle" => "modal", :href => "#LoginBox", :role => "button"}
%i.icon-user.icon-white
%strong
Login
This is what I get as error:
undefined local variable or method `current_user' for #<#<Class:0x007ff0a0544668>:0x007ff0a05414b8>
I really don't get what the problem is. Please help !
You have written your code in application controller instead of application helper
That is the reason why your method is not getting called
if you want to check if current user is logged in or not
you may just use before filter in application controller and call the method
whenever you dont need to check the method add skip before filter in that place

Rails 3 devise_for and STI

I have the following models:
User
Athlete < User
Coach < User
In my routes, I have the following:
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks", :registrations => "registrations" }
I am wanting to create a route for each sign_up path (ie: /sign_up/coach, /sign_up/athlete)... should I create two different registration controllers or is there a way to do this with just one registration controller?
You can use a single registration controller doing something like this:
class UsersController < Devise::RegistrationsController
private
def resource_class
params[:type].present? ? params[:type].classify.constantize : super
end
end
There are some other tweeks you would need to do. Whether that is worth it or not, I guess it depends on how similar the models actually are.
Hope it helps!
It would be good if you create separate controllers for coach and athlete:
devise_for :coach, :controllers => { :registrations => "coach_registrations" }
devise_for :athlete, :controllers => { :registrations => "athlete_registrations" }
class CoachRegistrationsController < Devise::RegistrationsController
end
class AthleteRegistrationsController < Devise::RegistrationsController
end
Thanks.

How can I default an ancestral relationship with cancan to an internal node of the tree?

I am using cancan to authorize my controller actions. One of classes where access is authorized by cancan is a tree, implemented with acts_as_ancestry. I'm having problems using load_and_authorize_resource when the user is not permitted to access the root level, but rather is allowed access starting at an interior node.
Here are some relavant class definitions:
class User < ActiveRecord::Base
belongs_to :organization, :inverse_of => :users
end
class Post < ActiveRecord::Base
belongs_to :organization, :inverse_of => :posts
end
class Organization < ActiveRecord::Base
has_ancestry :cache_depth => true
has_many :users, :inverse_of => :organization
has_many :posts, :inverse_of => :organization
end
The rules for managing posts are "You can manage posts in any organization below yours". My cancan abilities definition is this:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
# subtree_ids is added by acts_as_ancestry
can :manage, Post, {:organization_id => user.organization.subtree_ids}
end
end
In the controller, I have this (other actions omitted)
class PostsController < ApplicationController
load_and_authorize_resource :post
def index
end
def new
end
end
Everything works fine when the authorized user belongs to the root organization. However, when I login as a user authorized at an internal node, the index action works fine, but when the new action is invoked, I get a can-can authorization error.
Here is what I see in the log:
Access denied on new #<Post id: nil, organization_id: 1>
The organization_id 1 (the root) is coming from the schema:
create_table "posts", :force => true do |t|
t.integer "organization_id", :default => 1
end
With cancan, the new action will build a new Post and assign it to #post. When it does this, it will initialize all the attributes with values taken from the can definition in Abilities.rb. However, it will not do anything if those attributes are Arrays, Hashes or Ranges and the default value ends up coming from the schema.
How can I authorize users to manage posts in their subtree, but when they create a new post, default it to their organization?
In cancan, if the #post variable is already initialized by you, it will not call load_resource on it, only do the authorize part. See this part of the docs: https://github.com/ryanb/cancan/wiki/Authorizing-controller-actions, "Override loading".
So the simplest solution is to take control of the initialization yourself and make it what you need, like here:
class PostsController < ApplicationController
before_filter :initialize_post, :only => [:new, :create]
def initialize_post
#post = current_user.organization.posts.build(params[:post]||{:name=>'Smashing Kittens'})
end
load_and_authorize_resource :post
def index
end
def new
end
def create
end
end
You can see it working in this test project that I created from your post: https://github.com/robmathews/cancan_test.
I had a similar issue and ended up writing ancestry related permissions in blocks like so:
can :manage, Post do |post|
post.organization.subtree_ids.include?(user.organization_id)
end

How to use both Omniauth_callbacks controller and custom devise registrations controller

I have a custom registrations controller for devise set up, which is this:
devise_for :users, controllers: {registrations: "registrations"}
and in the controller:
class RegistrationsController < Devise::RegistrationsController
protected
def after_update_path_for(resource)
user_path(resource)
end
end
It works great.
However I also have omniauth authentication, which again works great...by itself:
devise_for :users, controllers: {omniauth_callbacks: "omniauth_callbacks"}
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def all
user = User.from_omniauth(request.env["omniauth.auth"])
if user.persisted?
flash.notice = "Signed in!"
sign_in_and_redirect user
else
session["devise.user_attributes"] = user.attributes
redirect_to sign_up_path
end
end
alias_method :linkedin, :all
alias_method :twitter, :all
end
However as you can probably already see my problem - I'm not sure how to get them to work together, as they both start with 'devise_for :users' and so whichever way round I place them in the routes file, one won't work.
How can I get them both working at the same time, so that the registrations controller only overrides the 'edit' and 'update' actions, while the omniauth_callbacks controller handles authentication?
Thanks
In routes.rb, you can put comma seperated paths for devise_for like this -
devise_for :users, controllers: {registrations: "registrations", omniauth_callbacks: "omniauth_callbacks"}
This will work.

How to add a UserProfile to a User when user signs up? (Devise, Rails 3)

I want to override Devise's RegistrationsContollers' create action so that when a user signs up, I can associate a UserProfile model with that user.
So, following the guidelines in the Devise Readme, I override the action:
#File app/controllers/registrations_controller.rb:
class Users::RegistrationsController < Devise::RegistrationsController
def create
# some code here..
self.user_profiles.build #Error (no method `user_profiles`)
current_user.user_profiles.build #Error (current_user is nil)
some other way???
end
end
#File routes.rb:
devise_for :users, :controllers => { :registrations => 'users/registrations' }
Devise is creating a record in the users table, but how do I associate a UserProfile with that record?
I've tried googling but I simply can't get this to work! Any help is much appreciated.
(I'm now using Devise 1.1.5 on Rails 3.0.3)
SOLVED:
Adding solution for benefit of others:
#File app/controllers/registrations_controller.rb:
class Users::RegistrationsController < Devise::RegistrationsController
def create
super
#user.build_user_profile
#user.user_profile.some_data = 'abcd'
#user.save!
end
end
self refers to the contoller not the model in this context.
Also, does the user model have many UserProfiles? Otherwise if they don't (ie they only have one), then you should use #user.build_user_profile, not #user.user_profiles.build
I'd also recommend doing this at the model level, not the controller level, using a callback such as before_create or after_create, ie:
class User < AR
has_one :user_profile
after_create :build_profile
def build_profile
self.build_user_profile
...
end
end