Devise's current_user only works for admins - ruby-on-rails-3

I've got a standard User model, it has in it an admin boolean. All's well and good for users that have that set to true, but for normal users I get this error:
undefined local variable or method `current_user'
app/models/doc.rb:18:in `mine'
app/controllers/docs_controller.rb:9:in `index'
The Doc model on line 18 reads like this:
def self.mine
where(:user_id => current_user.name, :retired => "active").order('created_at DESC')
end
My User model looks like this:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
attr_accessor :current_password
attr_accessible :name, :password, :password_confirmation, :current_password, :email, :remember_me, :admin
end
class Ability
include CanCan::Ability
def initialize(user)
can :manage, :all if user.admin
end
end
And in my application controller I have the following:
class ApplicationController < ActionController::Base
protect_from_forgery
after_filter :user_activity
rescue_from CanCan::AccessDenied do |exception|
redirect_to root_path
end
def admin?
self.admin == true
end
def authenticate_admin
redirect_to :new_user_session_path unless current_user && current_user.admin?
end
private
def user_activity
current_user.try :touch
end
end
I think that's everything relevant. I can't for the life of me figure this out.

the current_user helper is a controller method that is not accessible from a model. You should pass current user in as a parameter from the controller to the model.
def self.mine(current_user)
where(:user_id => current_user.name, :retired => "active").order('created_at DESC')
end
EDIT: Side note
It looks like user_id is a string in your logic. If this is what you are doing, you should reconsider. Setting up a belongs_to and a has_many with rails using identifiers in the database is far more maintainable. Using string ids is unconventional, and its a rabbit hole that ends in very bad places.

Related

One to one in rails aplication

i have question about proper way to do one to one association in rails.
I am using Devise GEM as user module and all users can have only one company so i made
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :company
end
and
class Company < ActiveRecord::Base
belongs_to :user
end
What is proper way to create company?? normally i made it like this:
i check if company exist if exist display message if not proceed to create. Is that good method?
def new
if Company.exists?(:user_id => current_user.id )
flash[:notice] = "Only One company is allowed."
redirect_to(:action => 'index')
end
end
def create
# Instantiate a new object using form parameters
#company = Company.new(company_params)
##company = Company.new(params[:page].merge(:user_id => 1))
# Save the object
if #company.save
# If save succeeds, redirect to the index action
flash[:notice] = "Company created successfully."
redirect_to(:action => 'index')
else
# If save fails, redisplay the form so user can fix problems
render('new')
end
end
If your form is properly created, it should be OK.
in your User form, you should use fields_for, and it should look like something like this :
<%= f.fields_for :company do |company_field| %>
<%= company_field.text_field :name %>
<% end %>
Edit : Don't forget to add nested attibutes : accepts_nested_attributes_for :address on the model user, below the has_one :company.
Nested attributes allow you to save attributes on associated records
through the parent.
Beside that, be carefull with the validation you wanted to do in the new method, the proper way to handle validation is to use ActiveRecord Validations.

Rails 3.0 devise account validation from admin to user - undefined method `edit_user_path'

I'm trying to make an admin account to validate the registration of a user, for that I have 2 devise models: admin and user.
I've followed these steps:
https://github.com/plataformatec/devise/wiki/How-To%3a-Require-admin-to-activate-account-before-sign_in
But from the view I get this error:
Undefined method `edit_user_path'
This is my app/models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me
def active_for_authentication?
super && approved?
end
def inactive_message
if !approved?
:not_approved
else
super # Use whatever other message
end
end
def self.send_reset_password_instructions(attributes={})
recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
if !recoverable.approved?
recoverable.errors[:base] << I18n.t("devise.failure.not_approved")
elsif recoverable.persisted?
recoverable.send_reset_password_instructions
end
recoverable
end
end
App/controllers/unapproved_users_controller.rb
class UnapprovedUsersController < ApplicationController
def index
if params[:approved] == "false"
#users = User.find_all_by_approved(false)
else
#users = User.all
end
end
end
App/views/unapproved_users.html.haml
%h1 Users
= link_to "All Users", :action => "index"
|
= link_to "Users awaiting approval", :action => "index", :approved => "false"
%table
- #users.each do |user|
%tr
%td= user.email
%td= user.approved
%td= link_to "Edit", edit_user_path(user)
This path makes the problem:
= link_to "Edit", edit_user_path(user)
Option #1 - Check rake routes for the correct helper
Option #2 - You need to setup an administrator interface to edit users as I'm pretty sure devise only provides the interface for current_user not for people wanting to edit another user.
Option #3 - Use something like RailsAdmin

Rails SRP Modules, attr_accessible

I'm learning SOLID and trying to introduce SRP into my rails app. I have the following user model with basic authentication:
class User < ActiveRecord::Base
attr_accessible :password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
def self.generate_random_password
return ActiveSupport::SecureRandom.hex(12)
end
end
I want to move all the authentication logic to a module like so:
module Authentication
attr_accessible :password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
def self.generate_random_password
return ActiveSupport::SecureRandom.hex(12)
end
end
And my user model would be like this:
class User < ActiveRecord::Base
include Authentication #SRP in action! :P
end
And now the errors begin:
undefined method `attr_accessible' for Authentication:Module
How would I fix this error? I am convinced this is the best start to introduce SRP to my Rails app.
Thanks
The attr_accessible method is called in the wrong scope. Take a look at Concerns to fix this:
http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
This would result in:
module Authentication
extend ActiveSupport::Concern
included do
attr_accessible :password, :password_confirmation
end
...
end
This will also take care of you class and instance method definitions.
NOTE: To be specific, this does not quite achieve SRP, since multiple responsibilities are still shared within the same class, even though they are separated into modules. Class composition through referencing or decorating would be a more strict solution , but I prefer the pragmatic approach of modules.

Rails/Heroku: undefined method `events' for nil:NilClass

I have a method that works locally on my machine but it fails in Heroku. Heroku logs say:
NoMethodError (undefined method `events' for nil:NilClass)
I have used heroku console for an equivalent of this method and it works so there is data that supports it. The method is:
def index
#events = current_user.school.events
end
I am using Devise which I believe gives me the current_user method. The equivalent, a = User.first.school.events yields the true instance value with data. The User.first yields correct data.
Here are my models:
class School < ActiveRecord::Base
#validates_presence_of :name
has_many :events, :dependent => :destroy
has_many :users, :dependent => :destroy
belongs_to :user
belongs_to :event
def self.fetch_for_name(_name)
school = self.new(:name => _name)
end
end
class User < ActiveRecord::Base
belongs_to :school
rolify
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :name, :email, :password, :password_confirmation, :remember_me
end
class Event < ActiveRecord::Base
belongs_to :school
end
It would be like me if I overlooked some simple, basic thing but if I can do this correctly in Heroku console, why would this method break. Another unrelated page works correctly on Heroku.
current_user is the user that is logged in. It doesn't necessarily mean User.first. This should be the same locally as on Heroku. If you're having trouble figuring out what user is logged in you can add this to your application controller
before_filter :debug
def debug
Rails.logger.info("Current User is: #{current_user.inspect}")
end
And then view the output with $ heroku logs --tail It should show you the current value of the current_user. At the end of the day what #thesis said is correct, you have a user that does not have a school associated with it.

Find on has_many :through

I have 3 models: Users, Customers, Issues. Below is the code for these models
Customer model:
class Customer < ActiveRecord::Base
belongs_to :se
belongs_to :user
has_many :issues
end
Issues model:
class Issue < ActiveRecord::Base
belongs_to :customer
end
Users model:
class User < ActiveRecord::Base
has_many :ses
has_many :customers
has_many :issues, :through => :customers
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me, :first_name, :last_name, :cell_ph, :area
end
I would like to display only the issues that belong to a particular user. I am having problems making this work. Can someone suggest how I might create an index method that would accomplish this?
Here is my index method where I'm trying to use devise's current_user method to identify the user who's logged in to the view:
def index
#issues = Issue.where(:user == :current_user)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #issues }
end
end
You can't do what you're doing because an Issue doesn't have a user.
According to Rails guides (second example on http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association session), you can nest the has_many using a has_many :through.
So you should be able to do this:
current_user.issues
In addition to Rodrigo's answer, you have some bad syntax on this line:
#issues = Issue.where(:user == :current_user)
That's never going to return any results because :user == :current_user is performing a comparison of two distinct Ruby Symbol objects. That always returns false, so your statement essentially equates to Issue.where(false).
This is closer to what you need:
#issues = Issue.where(:user => current_user)
This still doesn't fix the problem you have (Issue does not have many Users), but at least the meaning is correct.