Rails validate user entry - ruby-on-rails-3

I am working on a project and relatively very new to Rails. What I wanted to do is redirect the user to the username and email entry form. Here is my controller:
class UsersController < ApplicationController
def create
#user = User.create!(user_params)
flash[:notice] = "#{#user.user_id} was successfully created."
redirect_to movies_path
end
Here's my model:
class User < ActiveRecord::Base
validates :user_id, uniqueness: true
end
What I wanted to do is just send the user back to the new user view by using flash if user_id already exists.
Thank you for the help.

Related

Prevent sign in without invitation code in rails/devise

Scenario addressed: A visitor cannot sign in without a generic code to control user access during initial test of a website (Rails 5.1.6 with devise 4.4.3)
This is achieved by setting the controller as follows:
class ApplicationController < ActionController::Base
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:fullname, :invitation])
devise_parameter_sanitizer.permit(:account_update, keys: [:fullname, :phone_number, :description])
end
end
and then I have adjusted the user model with:
class User < ApplicationRecord
attr_accessor :invitation
validates :validate_invitation, presence: true, :on => :create
def validate_invitation
if self.invitation != "123"
self.errors[:base] << "Enter a valid invitation code"
end
end
When I proceed to the sign with a new user, it fails. The console returns the following:
Parameters: {... "user"=>{"fullname"=>"Jone", "invitation"=>"123",...}, "commit"=>"Sign up"}
However the sign in is not validated because: "Invitation can't be blank"
I can't see the mistake.
Add to the user class the following validation below "attr_accessor :invitation": validates :invitation, on: :create, presence: true, inclusion: { in: ["123"]}
and eliminate the def validate_invitation entirely.

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

Using flash to notify user of previous registration

I'm trying to use my Users controller to notify the user when their email has already been used in a registration, but even when the email already exists, I still get the error "Plase validate your input and try again," rather than "You've already registered! Thanks for being enthusiastic!" Is using the controller not the create way of achieving this behavior?
In the rails console (assuming "foo#bar.com" is in the database"), when I use user = User.new(name:"Example", email:"foo#bar.com") then User.find_by_email(user.email) it does return the proper User entry, so I'm not sure if I'm on the right track and just executing it incorrectly or what. Any ideas?
users_controller.rb:
class UsersController < ApplicationController
def new
#user = User.new(params[:user])
end
def create
#user = User.new(params[:user])
if #user.save
flash[:success] = "Thanks for supporting cofind! We'll be in touch!"
redirect_to root_path
UserMailer.welcome_email(#user).deliver
else
if #user.email == User.find_by_email(#user.email)
flash[:error] = "You've already registered! Thanks for being enthusiastic!"
redirect_to root_path
else
flash[:error] = "Plase validate your input and try again."
redirect_to signup_path
end
end
end
end
user.rb:
class User < ActiveRecord::Base
attr_accessible :email, :name
before_save { |user| user.email = email.downcase }
validates :name, presence: true
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
end
this line
if #user.email == User.find_by_email(#user.email)
checks the user's email (a string) against a user record (an ActiveRecord object) which will always be false. You should change that to
if User.where(email: #user.email).exists?

Rails remember_token session not working

I am new to Ruby on Rails. I am learning it through Michel Hartl's reference doc available on the internet. However i ran into a problem during sign-in of users, I suspect the before_save is not calling the create_remember_token method. I am trying to debug this issue from a very long time. My code is as follows:
user.rb file:
# == Schema Information
#
# Table name: users
#
# id :integer(4) not null, primary key
# name :string(255)
# email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# password_digest :string(255)
# username :string(255)
# remember_token :string(255)
#
class User < ActiveRecord::Base
def to_param
username
end
attr_accessible :name, :email, :password, :password_confirmation, :username
has_secure_password
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
session_helper.rb
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
current_user = user
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= user_from_remember_token
end
def signed_in?
!current_user.nil?
end
private
def user_from_remember_token
remember_token = cookies[:remember_token]
User.find_by_remember_token(remember_token) unless remember_token.nil?
end
end
sessions_controller.rb:
class SessionsController < ApplicationController
def new
end
def create
user=User.find_by_username(params[:session][:username])
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_to "/#/#{params[:session][:username]}"
else
flash.now[:error] = "Login failed! Please try again!"
render 'new'
end
end
def destroy
end
end
Please help me and let me know as to where the problem exists.
Cheers :)
What exactly is the problem that you are having during sign in?
The reason I ask is that the create_remember_token method is not supposed to be called during the sign-in process. It gets called when the user is saved (sign-up).
The sign-in process just fetches the token from the users table and copies it into the permanent cookie. The sign-in process looks roughly like this:
sign_in user --> session_helper.rb --> def sign_in(user) --> cookies.permanent[:remember_token] = user.remember_token --> back to session_controller.rb --> redirect_to ...
The before_save callbacks should only be called when the user is created (ie. when they sign up, not when they sign in). You don't show the whole sign-up/user creation flow in your code sample, but i assume it exists.
You can test whether create_remember_token is called (when the user is created) by running this command from the Rails console:
User._save_callbacks.select { |cb| cb.kind.eql?(:before) }.collect(&:filter).include?(:create_remember_token)
That should return true if and only if the create_remember_token function is being run on save. More details in the 'Debugging callbacks' section of the Callbacks API Documentation.
If the callback is called during the signup flow, the remember_token should be saved to the DB then. You can verify that by inspecting the user with the Rails console (User.last, after creating your test user).
What does your sign-up/user creation flow look like? What repro steps produce the problem you're describing?
You might have not used csrf meta tag in your layout. Try removing ' protect from forgery ' in application_controller.rb in controllers folder. Then try running the app again, if it works then you didnt add tags to your layout.
I had posted this question a year ago.
Now I am using the Devise gem for authentication. Everything is working as expected.
Thanks

How can I add a custom column in authlogic?

I've created a simple user system with authlogic using Rails 3. I want to add an "account_type" column to the database. How can I populate this column in the database when the user signs up? I have very very little experience with Rails.
Update: So I know somewhere in "#user = User.new(params[:user])" I need to add :account_type = "user". What's the right syntax for this though?
Here's what I have in my user controller:
class UserController < ApplicationController
before_filter :require_no_user, :only => [:new, :create]
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:notice] = "Registration successful!"
redirect_to root_url
else
render :action => :new
end
end
end
Thanks in advance!