Cant delete object after installing devise & cancan - ruby-on-rails-3

I installed Devise and Cancan. My user has role super_admin with options shown below:
def initialize(user)
user ||= User.new # guest user
can :manage, :all
end
all works well except deleting elements. When I'm trying to delete object:
<%= link_to 'Destroy', place, :method => :delete, :data => { :confirm => 'Are you sure?' } %>
it keeps logging me out and redirecting to sign_in page
My class looks like that:
class PlacesController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource

Ok, I figured it out.
My layout file did not have authenticity_token tag
<%= csrf_meta_tag %>
so POST and DELETE requests couldn't have been authenticated.

Related

Devise Session Limit Problems

Referring to an article: devise limit one session per user at a time
I have setup my Rails app as follows:
routes.rb
devise_for :users, :controllers => { :sessions => "my_sessions" }
Application Controller:
before_filter :check_concurrent_session
def check_concurrent_session
if is_already_logged_in?
sign_out_and_redirect(current_user)
end
end
def is_already_logged_in?
current_user && !(session[:token] == current_user.login_token)
end
my_sessions controller:
class MySessionsController < Devise::SessionsController
skip_before_filter :check_concurrent_session
def create
super
set_login_token
end
private
def set_login_token
token = Devise.friendly_token
session[:token] = token
current_user.login_token = token
current_user.save
end
end
When I wire this up and restart my Rails server it loads fine. However when attempting to login it quickly reverts to the login screen. Per my dev log I can see it hitting the MySessions controller:
Started GET "/users/sign_in" for 127.0.0.1 at 2012-08-30 10:51:24 -0500
Processing by MySessionsController#new as HTML
Rendered devise/sessions/new.html.erb within layouts/application (1.4ms)
Completed 200 OK in 16ms (Views: 15.8ms | ActiveRecord: 0.0ms)
Devise/Sessions/new
<h2>Secure Login</h2>
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
<div><%= f.label :login %>
<%= f.text_field :login, :placeholder => 'Username or Email' %></div><br />
<div><%= f.label :password %>
<%= f.password_field :password, :placeholder => '••••••••' %></div><br />
<div><%= f.submit "Login", :class => 'btn btn-inverse' %></div>
<% end %>
Even though it's hitting the override controller it's not doing anything after that. I've followed the article to a tee and it worked for another user. Can anyone look at my code and see what I'm doing wrong.
I'd really like to session limit properly as my app depends on it. I've tried using Devise Security Extension but keep getting an undefined method "unique_session_id" after following the instructions so I figured I'd try this out instead.
Thanks in advance, guys!
Won't
current_user && !(session[:token] == current_user.login_token)
always be true if you're logged in?
Which would explain the redirect since when you re-login, you're logged in so you need to login, repeat.

CanCan, Devise and the "current_user"

I have a simple setup with Cancan and Devise.
I wanna show the edit button only to "Admins" and Users which owns the "location":
So in the show.html.erb I have
<% if can? :manage, location, :user_id == current_user.id %>
<%= link_to 'Edit', edit_location_path %>
<% end %>
My ability.rb looks like this
if user.roles.include?('User')
can [:show, :index, :create], Location
can :manage, Location, :user_id => user.id
end
The locationController contains this on the very top:
load_and_authorize_resource
User Id is referenced in Location.user_id
But it does not show up the EDIT Button...
Did I miss something?
PS: user.id does not work in the view. and current_user.id does not work in the ability.rb
PPS: My roles are stored in an array eg: Roles ["User", "Admin"] and works well.
I've got it working with
can :manage, Location, :user_id => user.id.to_s
I hope it helps someone!

Devise: change password

I've been stuck on this for over 24hrs trying to follow other solutions posted here, but I can't get this to work. I'm new to Rails and need help!
I want to get my /users/edit page working so that I can simply change a users password. Originally, I wanted to do it without current_password but I don't mind leaving it in there as long as I can get the password changing and updating.
Here's what I did:
I followed the example in the Devise Wiki and inserted it into my Users controller which I specified to inherit from Devise::RegistrationsController
class UsersController < Devise::RegistrationsController
...
end
I changed my routes:
devise_for :users, :controllers => { :registrations => 'users' } do
match '/users' => 'users#index'
end
And here's my model:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessor :password, :password_confirmation, :current_password
attr_accessible :email, :password, :password_confirmation, :current_password, :remember_me, :full_name, :coach, :bio
validates :full_name, presence: true
end
I was assuming the UsersController I created would override the Registrations controller and that I would be able to change/update password. It works to the extent the redirect to root_path happens (which is only meant to happen after updating without current password) but the new password is not saved (I checked the logs and there was no SQL to show it was saved)...
Any ideas?
Try doing something similar to:
Devise Forgot Password for logged in user
This lets you have a separate view for changing the password.
The key is that I couldn't ever get it working in devise, so I wrote my own solution in the users controller and post to that instead of using the methods provided by devise.
add this to your user form where you want to be able to edit the password:
<%= form_for(#user, :url => url_for(:action => :do_reset_password) , :html => { :method => :post }) do |f| %>
<%= f.hidden_field :reset_password_token %>
<div><%= f.label :password, "New password" %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation, "Confirm new password" %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.submit "Change my password" %></div>
<% end %>
users controller:
def do_reset_password
id = params[:id]
# there may be a better way of doing this, devise should be able to give us these messages
if params[:user][:password] != params[:user][:password_confirmation]
flash[:alert] = "Passwords must match."
redirect_to :back
return
end
if #user.reset_password!(params[:user][:password],params[:user][:password_confirmation])
#user.save
respond_to do |format|
format.html { redirect_to '/home', notice: 'Your password has been changed.' }
end
else
flash[:alert] = "Invalid password, must be at least 6 charactors."
redirect_to :back
end
end
config/routes.rb
resource :users do
post 'do_reset_password'
end

Nested model form not working properly - need to pinpoint POST/GET redirect

I have a nested model form that isn't functioning properly. The POST is to the proper place, but then the GET reroutes me. So I'm wondering if anyone can help explain what I'm doing wrong.
I have two models: User and Profile. Code for them below:
User:
class User < ActiveRecord::Base
attr_accessor :password, :email
has_one :profile, :dependent => :destroy
accepts_nested_attributes_for :profile
...
end
Profile:
class Profile < ActiveRecord::Base
attr_accessible :first_name, :last_name, etc.
belongs_to :user
accepts_nested_attributes_for :user
...
end
New/Create from both models:
class UsersController < ApplicationController
def new
#user = User.new
if logged_in?
redirect_to current_user.profile
end
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to signup_path, :notice => 'User successfully added.'
else
render :action => 'new'
end
end
class ProfilesController < ApplicationController
def new
#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
def index
#profile = current_user.profile
end
My signup (two step process) mixes the models, so as I said I'm using a nested model form in my Users new.html.erb file. Code form_for and f.fields_for below:
<%= form_for(:user, :url => signup_path, :html => {:id => 'homepage'}) do |f| %>
<%= f.fields_for :profile do |f| %>
Now when I enter data into the form, my routes.rb file seems to POST to the proper place (/signup so profile can be filled out further), but GET routes me to /login.
Routes.rb:
match '/login' => "sessions#new", :as => "login"
match '/signup' => 'profiles#new', :as => "signup"
match 'skip/signup', :to => 'info#signupskip'
match 'skip/profiles/new', :to => 'profiles#newskip'
root :to => 'users#new'
resources :users
resources :profiles
In rails server:
Started POST "/signup" for 127.0.0.1 at Sun Aug 28 19:54:11 -0400 2011
Processing by ProfilesController#new as HTML
Started GET "/login" for 127.0.0.1 at Sun Aug 28 19:54:11 -0400 2011
Processing by SessionsController#new as HTML
Rendered sessions/new.html.erb within layouts/application (32.1ms)
I'm wondering if the problem is in my layouts/application file, specifically this code:
<% if logged_in? %>
<%= render 'layouts/header_in' %>
<% else %>
<%= render 'layouts/header_out' %>
<% end %>
Can anyone help explain to me what I'm doing wrong?
UPDATE:
I deleted the if/else argument in `layouts/application' and it was still redirected. So I'm back to wondering what's going on.
I believe your problem has to do with an inherent issue (though arguably not problem) with HTTP protocol. You cannot return a redirect to a POST request. Alternatives include calling the other method from within the first controller action, or rendering the correct page directly from that action, or some mix of both.

CanCan polymorphic resource access problem

i don't quite understand how to restrict access to links in this particular case with CanCan. I always get "Edit" link displayed.
So i believe the problem is in my incorrect definition of cancan methods(load_ and authorize_).
I have CommentsController like that:
class CommentsController < ApplicationController
before_filter :authenticate_user!
load_resource :instance_name => :commentable
authorize_resource :article
def index
#commentable = find_commentable #loading our generic object
end
......
private
def find_commentable
params.each { |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.includes(:comments => :karma).find(value)
end }
end
end
and i have in comments/index.html.erb following code that render file from other controller:
<%= render :file => "#{get_commentable_partial_name(#commentable)}/show.html.erb", :collection => #commentable %>
you can think about "#{get_commentable_partial_name(#commentable)}" like just "articles" in this case.
Content of "articles/show.html.erb":
<% if can? :update, #commentable %>
<%= link_to 'Edit', edit_article_path(#commentable) %> |
<% end %>
my ability.rb:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.role? :admin
can :manage, :all
elsif user.role? :author
can :read, [Article, Comment, Profile]
can :update, Article, :user_id => user.id
end
end
end
i have tried debug this issue like that
user = User.first
article = Article.first
ability = Ability.new(user)
ability.can?(:update, article)
and i always get "=> true" in ability check
Note: user.role == author and article.user_id != user.id
if you need more information please write
thank's for your time && sorry for my english
okay i figure it out, redetermined rules in ability.rb so now order is like guest->author->moderator->admin and problem is solved. I believe root of problem was in cancan logic which assumes that i need to redefine rules or do it in order i've show before