ActiveSupport::MessageVerifier::InvalidSignature in RegistrationsController#create - ruby

I'm currently working on a Rails 6 application with ActiveStorage installed. I'm using devise for authentication. I the the following error when trying to create a new user on the sign up form.
ActiveSupport::MessageVerifier::InvalidSignature in RegistrationsController#create
I think the reason comes from trying to set a default avatar to the model User. When a user is created I'm trying to set astronaut.svg as the default avatar.
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :posts
has_one_attached :avatar
before_create :set_defaults
def set_defaults
self.avatar = 'assets/images/astronaut.svg' if self.new_record?
end
end
How to fix?

This code works for me:
def set_defaults
if self.new_record?
self.avatar = Rack::Test::UploadedFile.new(
Rails.root.join('app/assets/images/astronaut.png'),
'image/png',
)
# file = File.new(Rails.root.join('app/assets/images/astronaut.png'))
# self.avatar = Rack::Test::UploadedFile.new(
# file.path,
# Mime::Type.lookup_by_extension(File.extname(file).strip.downcase[1..-1]).to_s,
# )
end
end
However I recommend not to send default image in before_create, but use a helper instead:
def user_avatar(user)
if user.avatar.attached?
image_tag user.avatar
else
image_tag 'astronaut.png'
end
end

Related

irb does not have access to my models (NameError: uninitialized constant)

I am receiving this error when trying to create a new 'Pin' in IRB. For example:
irb(main):001:0> #pin = Pin.first
NameError: uninitialized constant Pin
OR
irb(main):001:0> #pin = Pin.new
NameError: uninitialized constant Pin
I must of changed something as it was working before. Unfortunately, I cannot find the error
Here is my pins controller:
class PinsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
before_action :correct_user, only: [:edit, :update, :destroy]
before_action :set_pin, only: [:show, :edit, :update, :destroy]
def index
#pins = Pin.all
end
def show
#pin = Pin.find params[:id]
end
def new
#pin = Pin.new
end
def edit
end
def create
#pin = Pin.new(pin_params)
if #pin.save
redirect_to #pin, notice: 'Pin was successfully created.'
else
render action: 'new'
end
end
def update
if #pin.update(pin_params)
redirect_to #pin, notice: 'Pin was successfully updated.'
else
render action: 'edit'
end
end
def destroy
#pin.destroy
redirect_to pins_url
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pin
#pin = Pin.find(params[:id])
end
def correct_user
#pin = current_user.pins.find(params[:id])
redirect_to pins_path, notice: "Not allowed!" if #pin.nil?
end
# Never trust parameters from the scary internet, only allow the white list through.
def pin_params
params.require(:pin).permit(:description)
end
end
Here is are my associations, pin.rb
class Pin < ApplicationRecord
belongs_to :user
end
And my associations for User.rb:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :pins
end
and my routes
Rails.application.routes.draw do
resources :pins
devise_for :users
root "pages#home"
get "about" => "pages#about"
end
irb does not automatically load your Rails environment, which is why it does not have access to your models (or helpers, or database, or anything else). However, the "rails console" is an irb session that does load all of your Rails classes, database connections, etc.
To start the rails console:
rails c
Which is shorthand for:
rails console
This starts the rails console for your development environment. You can make it connect to your test environment:
rails c RAILS_ENV=test
or to your production environment:
rails c RAILS_ENV=production

Role based authorization with cancan doesn't works Rails 4 - Ruby 2.1

I use cancan (1.6.10) and devise (3.2.2), I have been implementing authorization using this guide as recommended by cancan's author, I need to assign multiple roles to a user then I decided store it into a single integer column using a bitmask (I added a column named "roles_mask" to user model).
I have this files involved:
user.rb
edit.html.erb
I'm aware that I folowed word by word of this guide except the lines that I wrote for indicate that roles is a accessible attribute:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_filter :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:email, :password, :password_confirmation, :current_password, :roles) }
end
end
When update a user (logged), all fields are updated except :roles_mask =/, I don't understand why roles field is not captured. I think there's something that I don't achieve to see. anyone can help me?
*Solution:
Using cancancan (support for Rails 4) and change application_controller.rb file it works (as roles is a non-scalar attribute).
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_filter :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:email, :password, :password_confirmation, :current_password, roles: []) }
end
end
CanCan does not support Rails 4. You can however use CanCanCan, which is Rails4 friendly: https://github.com/CanCanCommunity/cancancan

can not find the user has a role of admin

Now I am try to find whether the user has permissions to do something as admin.
this is the user model code:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
# attr_accessible :title, :body
has_many :user_roles
has_many :roles, :through => :user_roles
def has_role?(role)
case role
when :admin then admin?
when :member then true
else false
end
end
def admin?
roles.each do |role|
return true if role.name == 'admin'
end
return false
end
end
Now there is a user which has a role name = admin and the test code is here:
command:rails c
user = User.find(1)
user.has_role?('admin')
result is :
=> false
why is it not true?
what is more I think the admin? method needs some refactoring.Now it is augly but I don`t know how to refactor ):
It's because of you use string in method argument and symbol in case statement.
It may be better to refactor has_role? method to something like this:
def has_role?(role)
case role.to_s
when 'admin' then admin?
when 'member' then true
else false
end
end
.to_s is used to convert non-strings (such as symbols) to strings, so you may call has_role? :admin and has_role? 'admin' with equal result.
Also, your admin? method looks very ugly.
You may rewrite it equally to:
def admin?
roles.any? { |r| r.name == 'admin' }
end
Or write more generic has_role? as:
def has_role?(role)
roles.any? { |r| r.name == role.to_s }
end

Use CanCan Authorization along with Custom Authentication in Rails 3

I am new to Rails and have been developing an app in rails 3 after following a Lynda.com tutorial where Kevin Skoglund showed us a way to authenticate a user using SHA1 Digest. I used that in my app and there is a need now to put in some Authorization. When I searched around, I found CanCan to be one of the better ones for authorization in rails. However, CanCan seems to be mostly implemented using Devise or Authlogic authentication and not custom authentication.
I wanted to know if it is at all possible to use CanCan if we use custom authentication, like I did. Is so, how to go about getting CanCan to work ?
It looks like CanCan needs some 'create_user' to be present but I am not sure how/where to create it.
Another alternative that I thought would be to put in my custom check on every page to check the user role and redirect them to an error page if they are unauthorized but that seems like a bad way to approach this problem...Your views on this please.
Please let me know if you need any additional information. I am using Ruby 1.9.3 and Rails 3.2.1.
Below is the way I have my current authentication set up. Any help would be greatly appreciated.
access_controller.rb
class AccessController < ApplicationController
before_filter :confirm_logged_in, :except => [:login, :attempt_login, :logout]
def attempt_login
authorized_user = User.authenticate(params[:username], params[:password])
if authorized_user
session[:user_id] = authorized_user.id
flash[:notice] = "You are logged in"
redirect_to(:controller => 'orders', :action => 'list')
else
flash[:notice] = "Invalid Username/password combination"
redirect_to(:action => 'login')
end
end
def logout
session[:user_id] = nil
flash[:notice] = "You have been logged out"
redirect_to(:action => 'login')
end
end
user.rb (User Model)
require 'digest/sha1'
class User < ActiveRecord::Base
has_one :profile
has_many :user_roles
has_many :roles, :through => :user_roles
attr_accessor :password
attr_protected :hashed_password, :salt
def self.authenticate(username="", password="")
user = User.find_by_username(username)
if user && user.password_match(password)
return user
else
return false
end
end
def password_match(password="")
hashed_password == User.hash_with_salt(password, salt)
end
validates_length_of :password, :within => 4..25, :on => :create
before_save :create_hashed_password
after_save :clear_password
def self.make_salt(username="")
Digest::SHA1.hexdigest("Use #{username} with #{Time.now} to make salt")
end
def self.hash_with_salt(password="", salt="")
Digest::SHA1.hexdigest("Put #{salt} on the #{password}" )
end
private
def create_hashed_password
unless password.blank?
self.salt = User.make_salt(username) if salt.blank?
self.hashed_password = User.hash_with_salt(password, salt)
end
end
def clear_password
self.password = nil
end
end
ApplicationController.rb
class ApplicationController < ActionController::Base
protect_from_forgery
private
def confirm_logged_in
unless session[:user_id]
flash[:notice] = "Please Log In"
redirect_to(:controller => 'access', :action => 'login')
return false
else
return true
end
end
end
I recommend first reading or watching the Railscast about CanCan. It is produced by the author of this gem and therefore very informative:
http://railscasts.com/episodes/192-authorization-with-cancan
You can also get help on the Github page:
https://github.com/ryanb/cancan
Somehow, you need to fetch the currently logged in user. This is what the current_user method does, and it needs to be defined on the users controller. Try something like this:
class UsersController < ApplicationController
# your other actions here
def current_user
User.find(session[:user_id])
end
end
Then, you should be able to use CanCan as described in the resources above.

params[:token] not set with devise

I'm trying to implement Devise but new to it.
When I request .../api/v1/projects.json, I get 'undefined method admin? for nil:NilClass', which I'm assuming happens because params[:token] is not being set:
class Api::V1::ProjectsController < Api::V1::BaseController
def index
respond_with(Project.for(current_user))
end
end
--
class Project < ActiveRecord::Base
...
def self.for(user)
user.admin? ? Project : Project.readable_by(user)
end
end
--
class User < ActiveRecord::Base
before_save :ensure_authentication_token
devise :database_authenticatable, :registerable, :token_authenticatable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
...
end
--
class Api::V1::BaseController < ActionController::Base
before_filter :authenticate_user
respond_to :json
private
def authenticate_user
#current_user = User.find_by_authentication_token(params[:token])
end
def current_user
#current_user
end
end
Does anyone know how/where to set params[:token] with Devise?
Apparently I misunderstood the documentation, and token is passed in through the URL:
.../api/v1/projects.json?token=s28seWhpPVWkhMU7sszM
Problem solved, I guess.

Resources