Rails 4 has_secure_password - ruby-on-rails-4

In a Rails 4 app -- I am getting this error when trying to create a simple User in my console.
RuntimeError:
Password digest missing on new record
My model, controller, and schema looks like:
class User < ActiveRecord::Base # User.rb
has_secure_password
end
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to root_path, notice: "Thank you for signing up!"
else
render "new"
end
end
private
def user_params
params.require(:user).permit(:email, :name, :password, :password_confirmation)
end
end
create_table "users", force: true do |t| #db/schema.rb (edited for brevity)
t.string "email"
t.string "name"
t.text "password_digest"
t.datetime "created_at"
t.datetime "updated_at"
end
I am using postgresql, and am not sure if this is a bug, or if I have missed something simple.
Thanks,

In Rails 4 all of the attributes are mass assigned by default so you don't need to use attr_accesible. Now you have to state which ones you want to protect. you would write it like this
attr_protected :admin
The error that you are getting gets raised when password_digest is blank. It probably has something to do with your attr_accesor:. Can I see your view?

I had exact the same problem but that part here solved my problem. The password_confirmation could not be stored because it was not a permit parameter
def user_params
params.require(:user).permit(:name, :password_digest, :password, :password_confirmation)
end

I did it in rails 4:
for use "has_secure_password" you have to use the parameter password_digest
Schema Information = name :string, password_digest :string
class User < ActiveRecord::Base
has_secure_password
validates :name, presence: true, uniqueness: true
validates_presence_of :password, :on => :create
end
and the controller
def user_params
params.require(:user).permit(:name, :password_digest,
:password, :password_confirmation)
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to users_url, notice: "User #{#user.name} was successfully created.'"}
format.json { render action: 'show', status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end

Related

Getting an error message on Michael Hartl's Ruby on Rails Tutorial: NoMethodError in MicropostsController#create, how do I avoid getting this message?

Can't add or edit a new micropost in my toy_app (Chapter 2 of the Rails Tutorial). Before I added users and microposts with no problem. Then I specified the has_many / belongs_to relationship and ever since I'm getting:
"NoMethodError in MicropostsController#create undefined method `content' for
Did you mean? context context= context?" when I try to create and microposts, and a similar message when updating a micropost.
It might be worth nothing that I only had one user, and the user id was "3"... not sure why it wouldn't be 1. I've since deleted all microposts and still only have 1 user. How do I avoid this error message? If anyone could help I would greatly appreciate it.
The Microposts Controller:
class MicropostsController < ApplicationController
before_action :set_micropost, only: [:show, :edit, :update, :destroy]
# GET /microposts
# GET /microposts.json
def index
#microposts = Micropost.all
end
# GET /microposts/1
# GET /microposts/1.json
def show
end
# GET /microposts/new
def new
#micropost = Micropost.new
end
# GET /microposts/1/edit
def edit
end
# POST /microposts
# POST /microposts.json
def create
#micropost = Micropost.new(micropost_params)
respond_to do |format|
if #micropost.save
format.html { redirect_to #micropost, notice: 'Micropost was successfully created.' }
format.json { render :show, status: :created, location: #micropost }
else
format.html { render :new }
format.json { render json: #micropost.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /microposts/1
# PATCH/PUT /microposts/1.json
def update
respond_to do |format|
if #micropost.update(micropost_params)
format.html { redirect_to #micropost, notice: 'Micropost was successfully updated.' }
format.json { render :show, status: :ok, location: #micropost }
else
format.html { render :edit }
format.json { render json: #micropost.errors, status: :unprocessable_entity }
end
end
end
# DELETE /microposts/1
# DELETE /microposts/1.json
def destroy
#micropost.destroy
respond_to do |format|
format.html { redirect_to microposts_url, notice: 'Micropost was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_micropost
#micropost = Micropost.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def micropost_params
params.require(:micropost).permit(:context, :user_id)
end
end
Microposts model:
class Micropost < ApplicationRecord
belongs_to :user
validates :content, length: { maximum: 140 }
end
Users model:
class User < ApplicationRecord
has_many :microposts
end
Users Controller
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
#users = User.all
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'User was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :email)
end
end
schema.rb:
ActiveRecord::Schema.define(version: 20171222133429) do
create_table "microposts", force: :cascade do |t|
t.text "content"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
In your micropost_params you have permitted context. I assume it should be a content. Please check your schema.rb to verify what columns does your microposts table have.

Fliendly_ID - URL not being displayed

I am new to ROR and working on a small project. Recently I added the friendly ID gems and followed the instruction on the documentation. But I can't seem to get the URL working. I added the friendly id to communities model which is basically your posts model.
Route code:
class Community < ActiveRecord::Base
extend FriendlyId
friendly_id :title, use: [:slugged, :history]
validates :title, :length => { :minimum => 5 }
has_attached_file :post_image, :styles =>
{ :medium => "300x300>", :thumb => "100x100>", :large => "1280x720", :headline => "1280x720"}
validates_attachment_content_type :post_image, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
belongs_to :member
has_many :comments
scope :newest_first, lambda { order("communities.created_at DESC")}
scope :without_community, lambda{|community| community ? {:conditions => ["community.id != ?", #community.id]} : {} }
# def to_param
# "#{id}-#{title.parameterize}"
# end
end
I even tried the to_param to get the URL's. But nothing seems to work.
Controller code:
class CommunitiesController < ApplicationController
before_action :set_community, only: [:show, :edit, :update, :destroy]
layout "community"
before_filter :authenticate_member!, except: [:index, :show]
require 'will_paginate/array'
# GET /communities
# GET /communities.json
def index
#communities = Community.newest_first.friendly.where(params[:id]).paginate(page: params[:page], per_page: 9)
end
# GET /communities/1
# GET /communities/1.json
def show
#communities = Community.newest_first.friendly.where(params[:title]).paginate(page: params[:page], per_page: 5).where('id NOT IN (?)', #community.id)
end
# GET /communities/new
def new
#community = Community.new({:member_id => current_member.id})
end
# GET /communities/1/edit
def edit
end
# POST /communities
# POST /communities.json
def create
#community = Community.new(community_params)
respond_to do |format|
if #community.save
format.html { redirect_to #community, notice: 'Post: #{#community.title.capitalize} was successfully created.' }
format.json { render :show, status: :created, location: #community }
else
format.html { render :new }
format.json { render json: #community.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /communities/1
# PATCH/PUT /communities/1.json
def update
respond_to do |format|
if #community.update(community_params)
format.html { redirect_to #community, notice: 'Post: #{#community.title.capitalize} was successfully updated.' }
format.json { render :show, status: :ok, location: #community }
else
format.html { render :edit }
format.json { render json: #community.errors, status: :unprocessable_entity }
end
end
end
# DELETE /communities/1
# DELETE /communities/1.json
def destroy
#community.destroy
respond_to do |format|
format.html { redirect_to communities_url, notice: 'Post: #{#community.title.capitalize} was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_community
#community = Community.friendly.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def community_params
params.require(:community).permit(:name,:post_image, :title, :content, :member_id)
end
end
But If I type the URL like http://localhost:3000/communities/post.title I am able to go directly to the post. That means the slugs have been created and they are working kind of. But I can't seem to get them displayed on the URL.
I have tried many permutation and combinations but nothing seems to work.
Would really appreciate any help. Let me know if there is any other specific code you require.
FYI: Migrations code:
class AddSlugToCommunities < ActiveRecord::Migration
def change
add_column :communities, :slug, :string, limit: 191
add_index :communities, :slug, unique: true
end
end
Friendly_ID migration code:
class CreateFriendlyIdSlugs < ActiveRecord::Migration
def change
create_table :friendly_id_slugs do |t|
t.string :slug, :null => false, limit: 191
t.integer :sluggable_id, :null => false
t.string :sluggable_type, :limit => 50
t.string :scope, limit: 191
t.datetime :created_at
end
add_index :friendly_id_slugs, :sluggable_id
add_index :friendly_id_slugs, [:slug, :sluggable_type]
add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope], :unique => true
add_index :friendly_id_slugs, :sluggable_type
end
end
Went deeper into the code and found that slugs were being made. its just that the URL was not being linked properly. Made a few changes to the links to to use slugs instead of :id to get it working.
Thanks anyways #uzaif

Rails has_many :through association: retrieve foreign attribute through foreign key

In our Rails app, there are 3 models:
class User < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :calendars, through: :administrations
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
end
And here are the corresponding migrations:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.timestamps null: false
end
end
end
class CreateAdministrations < ActiveRecord::Migration
def change
create_table :administrations do |t|
t.references :user, index: true, foreign_key: true
t.references :calendar, index: true, foreign_key: true
t.string :role
t.timestamps null: false
end
end
end
class CreateCalendars < ActiveRecord::Migration
def change
create_table :calendars do |t|
t.string :name
t.timestamps null: false
end
end
end
EDIT: here is also our UsersController:
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: [:index, :destroy]
def index
#users = User.paginate(page: params[:page], :per_page => 10)
end
def show
#user = User.find(params[:id])
#administrations = #user.administrations
#calendar = current_user.calendars.build if logged_in?
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
#user.send_activation_email
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email,
:password, :password_confirmation)
end
# Before filters
# Confirms the correct user.
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless current_user?(#user)
end
# Confirms an admin user.
def admin_user
redirect_to(root_url) unless current_user.try(:admin?)
end
end
Once a user is logged in (authentication system already up and running), we want to display on his profile (users#show), all the calendars he has created.
We have seeded the database with the following instances:
User.create!(first_name: "Andy") # This user's id is 1.
Calendar.create!(name: "CalendarA")
Calendar.create!(name: "CalendarB")
Calendar.create!(name: "CalendarC")
Administration.create!(user_id: 1, calendar_id: 1, role: "Creator")
Administration.create!(user_id: 1, calendar_id: 2, role: "Editor")
Administration.create!(user_id: 1, calendar_id: 3, role: "Viewer")
Then, we have created a _administration.html.erb partial:
<li id="administration-<%= administration.id %>">
<span class="name"><%= administration.calendar_id %></span>
</li>
And included it in our user show.html.erb file:
<p><%= #user.first_name %>'s calendars</p>
<% if #user.administrations.any? %>
<%= render #administrations %>
<% end %>
And this is working, we get:
Andy's calendars:
1
2
3
However, what we would like to get for each user, is not only the ids of his calendars, but their names too, like this:
Andy's calendars:
1 CalendarA
2 CalendarB
3 CalendarC
So we tried to update the _administration.html.erb partial as follows:
<li id="administration-<%= administration.id %>">
<span class="name"><%= administration.calendar_id.name %></span>
</li>
Which results in the following error:
NoMethodError in UsersController#show
undefined method `name' for 1:Fixnum
Application Trace | Framework Trace | Full Trace
app/views/administrations/_administration.html.erb:2:in `_app_views_administrations__administration_html_erb__2225316747000531998_70329866860100'
app/views/users/show.html.erb:32:in `_app_views_users_show_html_erb___891585127045041471_70329832995240'
How can we access the "foreign" attribute name from the calendar model through the foreign key calendar_id in the join administration model?
administration.calendar.name should work if your associations are set up correctly.
Alternatively, you could add this method to Administration:
def calendar_name
calendar.name
end
and then just call administration.calendar_name

Can't add custom Devise field through view

I've been at this for days, and cannot figure out the problem. When I attempt to Sign Up, it appears to work, but when I check the rails console, it shows no username. I'm able to add one from there and it works fine, but using my Sign Up view it never works. Only the fields that were created when I installed Devise work. I've also added First and Last Name, but I only attempted to get Username working, so the code for names is incomplete. If I've left anything important out, let me know. I'd REALLY appreciate the help.
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
protected
def configure_devise_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:email, :username, :password, :password_confirmation)
end
end
.
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates :username, :uniqueness => {:case_sensitive => false}
has_many :posts
has_many :offers
has_many :requests
has_one :profile
def name
"#{first_name} #{last_name}"
end
protected
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
login = conditions.delete(:login)
where(conditions).where(["lower(username) = :value", { :value => login.downcase }]).first
end
end
.
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %>
<%= f.email_field :email, autofocus: true %></div>
<div><%= f.label :username %>
<%= f.text_field :username%><div>
<div><%= f.label :first_name %>
<%= f.text_field :first_name %><div>
...
.
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
def show_user
#user = current_user
render 'show'
end
def index
#user = User.all
end
def new
#user = User.new
render profiles_path
end
def create
#user = User.new(user_params)
if #user.save
redirect_to posts_path, notice: 'User successfully added.'
else
render profiles_path
end
end
def edit
end
def update
if #user.update(user_params)
redirect_to posts_path, notice: 'Updated user information successfully.'
else
render action: 'edit'
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:name, :first_name, :last_name, :email, :username)
end
end
.
class RegistrationsController < Devise::RegistrationsController
def update
new_params = params.require(:user).permit(:email,
:username, :current_password, :password,
:password_confirmation)
change_password = true
if params[:user][:password].blank?
params[:user].delete("password")
params[:user].delete("password_confirmation")
new_params = params.require(:user).permit(:email,
:username)
change_password = false
end
#user = User.find(current_user.id)
is_valid = false
if change_password
is_valid = #user.update_with_password(new_params)
else
#user.update_without_password(new_params)
end
if is_valid
set_flash_message :notice, :updated
sign_in #user, :bypass => true
redirect_to after_update_path_for(#user)
else
render "edit"
end end
end
Schema:
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "first_name"
t.string "last_name"
t.string "username"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
Add this to your ApplicationController
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
end
end
Source: https://github.com/plataformatec/devise#strong-parameters

ActiveModel::ForbiddenAttributesError - Rails4

Environment:
Windows 8.1
Rails4
Ruby 2
I am using Devise and I have two separate controllers: users_controller.rb and registrations_controller.rb.
Following is my registrations_controller.rb:
class RegistrationsController < Devise::RegistrationsController
before_filter :update_sanitized_params, if: :devise_controller?
def update_sanitized_params
devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:first, :last,
:email, :password,
:password_conf, :password_changed_at)}
devise_parameter_sanitizer.for(:account_update) {|u| u.permit(:first, :last, :salutation,
:email, :password,
:password_conf, :password_changed_at, :current_passwor)}
end
# GET /registrations/new
def new
super
end
# POST /registrations
# POST /registrations.json
def create
#user = User.new(registration_params)
#user.email = #user.email.downcase
##user.slug = "#{#user.first.downcase}_#{#user.last.downcase}_#{#user.email}"
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: t('registration_successfully_created') }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /registrations/1
# DELETE /registrations/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to registrations_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_registration
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def registration_params
params[:user]
end
end
and following is my User model: user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:password_expirable, :confirmable, :lockable, :timeoutable
validates :first, presence: true
validates :last, presence: true
validates :email, :email => true, presence: true, uniqueness: {case_sensitive: false}
before_save { |user| user.email = email.downcase }
end
When I try to create a new user, I get an error message:
ActiveModel::ForbiddenAttributesError
The following line is highlighted in the registrations controller:
#user = User.new(registration_params)
Witht the additional debug information:
{"utf8"=>"✓", "authenticity_token"=>"CRwY4emBZJXhH7kMNGQZR5H1D3D0IJrHCnBzs5PTE8U=", "user"=>{"email"=>"xxxx#jkjjjkj.com", "password"=>"xxxxxxx", "password_confirmation"=>"xxxxxxx", "first"=>"John", "last"=>"Doe"}, "commit"=>"Create User", "action"=>"create", "controller"=>"registrations"}
Any ideas?
You have defined a method for strong parameters but you cannot just return the params hash - instead you have to specifically whitelist the attributes you wish to pass on to the model.
def registration_params
params.require(:user).permit(:email, :password, :password_confirmation, ...) # etc for the rest of your attributes
end