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
Related
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
I am trying to model my first rails 4 project to make the leap from tutorial to the real world.
The app is a horse show signup.
The user (devise) adds an 'entry'.
The entry can consists one or more 'rides'
Each ride can have a single 'horse' and a single 'rider' (nested forms would allow user to select existing horse and rider or create new one via form during new entry create.
I started to do some nested web forms with Cocoon and Formtastic:
https://github.com/nathanvda/cocoon
buy I have problems with saving related data to tables.
When I save my entry the rides table contains correct values for:
test, entry_id, but not horse_id
The entry table has no ride_id value. It only has user_id (I set in controller manually)
My questions are:
I am sure I am missing a few conceptual concepts but do I have my models associations set up correctly?
How do I edit my current forms to save data correctly?
When I debug in the controller I get what looks to be an odd param value:
{"utf8"=>"√", "authenticity_token"=>"xxxxxxxxxxxxxx=", "entry"=>{"show_date"=>"10/26/2014", "rides_attributes"=>{"1407930343404"=>{"test"=>"Intro B", "horses"=>{"name"=>"Plain Horse", "_destroy"=>""}}}}, "commit"=>"Create Entry", "action"=>"create", "controller"=>"entries"}
I thought I would see 'horses_attributes' within the 'rides_attributes' hash but instead I see just 'horses'.
Any clarification including link to examples would be very appeciated.
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :entries
has_many :rides, :through => :entries
has_many :horses, :through => :entries
has_many :riders, :through => :entries
end
class Entry < ActiveRecord::Base
belongs_to :user
has_many :rides, :dependent => :destroy
has_many :horses, :through => :rides
has_many :riders, :through => :rides
accepts_nested_attributes_for :rides, :allow_destroy => true
accepts_nested_attributes_for :horses
accepts_nested_attributes_for :riders
end
class Ride < ActiveRecord::Base
belongs_to :entry
belongs_to :user
has_one :horse #, :dependent => :destroy
has_one :rider
accepts_nested_attributes_for :horse
accepts_nested_attributes_for :rider
end
class Horse < ActiveRecord::Base
belongs_to :ride # :dependent => :destroy
belongs_to :user, :dependent => :destroy
end
class Rider < ActiveRecord::Base
#belongs_to :ride #, :dependent => :destroy
belongs_to :user, :dependent => :destroy
has_many :rides
end
Here is my partial schema:
create_table "entries", force: true do |t|
t.date "show_date"
t.integer "user_id"
t.integer "ride_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "entries", ["ride_id"], name: "index_entries_on_ride_id", using: :btree
add_index "entries", ["user_id"], name: "index_entries_on_user_id", using: :btree
create_table "horses", force: true do |t|
t.string "name"
t.string "horse_ncdcta"
t.string "owner_fname"
t.string "owner_lname"
t.date "coggins_date"
t.integer "ride_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
end
add_index "horses", ["ride_id"], name: "index_horses_on_ride_id", using: :btree
create_table "riders", force: true do |t|
t.string "first_name"
t.string "last_name"
t.string "rider_ncdcta"
t.boolean "senior"
t.boolean "liability_signed"
t.integer "ride_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "riders", ["ride_id"], name: "index_riders_on_ride_id", using: :btree
create_table "rides", force: true do |t|
t.string "test"
t.integer "entry_id"
t.integer "rider_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "horse_id"
end
add_index "rides", ["entry_id"], name: "index_rides_on_entry_id", using: :btree
add_index "rides", ["rider_id"], name: "index_rides_on_rider_id", using: :btree
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 "phone"
end
partial entry controller:
def new
#user=current_user
#entry=Entry.new
end
def create
#entry = Entry.new(entry_params)
#entry.user_id=current_user[:id]
respond_to do |format|
if #entry.save
# example of params value
# {"utf8"=>"√", "authenticity_token"=>"xxxxxxxxxxxxxx=", "entry"=>{"show_date"=>"10/26/2014", "rides_attributes"=>{"1407930343404"=>{"test"=>"Intro B", "horses"=>{"name"=>"Plain Horse", "_destroy"=>""}}}}, "commit"=>"Create Entry", "action"=>"create", "controller"=>"entries"}
debugger
format.html { redirect_to #entry, notice: 'Entry was successfully created.' }
format.json { render :show, status: :created, location: #entry }
else
format.html { render :new }
format.json { render json: #entry.errors, status: :unprocessable_entity }
end
end
end
def entry_params
# added ids based on comments below
params.require(:entry).permit(:show_date, rides_attributes: [:id, :test, :_destroy, horses_attributes: [:name, :id]] )
end
views:
_form.html.haml
= semantic_form_for #entry do |f|
= f.inputs do
= f.label :show_date, "Show Date"
= f.input :show_date, :as => :select, :collection => [['08/03/2014', '08/03/2014'], ['09/14/2014', '09/14/2014'], ['10/26/2014', '10/26/2014'], ['11/15/2014', '11/15/2014']]
%h3 Rides
#rides
= f.semantic_fields_for :rides do |ride|
= render 'ride_fields', :f => ride
.links
= link_to_add_association 'add ride', f, :rides
= f.actions do
= f.action :submit
_ride_fields.html.haml
.nested-fields
= f.inputs do
= f.label :test, "Test"
= f.input :test, :as => :select, :collection => [['Intro A', 'Intro A'], ['Intro B', 'Intro B'], ['Intro C', 'Intro C']]
= f.semantic_fields_for :horses do |horse|
= render 'horse_fields', :f => horse
= link_to_add_association 'add horse', f, :horse
_horse_fields.html.haml
.nested-fields
=f.inputs do
= f.input :name
.links
= link_to_add_association 'add horse', f, :horse
Here's what I think is happening, you're nesting horse within Rides instead of Entry. Ride accepts nested attributes for a has_one horse relationship so you're seeing 'horses'. If you submitted horses against the Entry (which has a has_many relationship) you'd see horses_attributes.
In this section of _form.html.haml you assigned ride to f
= render 'ride_fields', :f => ride
And then in your _ride_fields.html.haml you use that f to create a nested form which is being created off the ride variable (Ride has_one horse).
= f.semantic_fields_for :horses do |horse|
= render 'horse_fields', :f => horse
Because your Ride model has accepts_nested_attributes_for :horse you're seeing horses within the Ride. To see horses_attributes you'll want to create horses against the Entry (which accepts the nested attributes for "horses").
I believe you can fix it by changing the render like this (pass in the Entry model form):
= render 'ride_fields', :f => ride, :e => f
And then the horse nested form like this (from f to e):
= e.semantic_fields_for :horses do |horse|
= render 'horse_fields', :f => horse
When using nested attributes the symbol you pass to form_for has to match the association name. You are doing
f.semantic_fields_for :horses
But rides doesn't have a horses assocation, only a horse association. Because of this rails doesn't realise that you're trying to use nested attributes at all, which is why the data is nested under the key "horses" rather than "horses_attributes". You will of course need to change the permitted params to match.
In addition you don't need all the stuff to manage adding extra horse fields for a ride if a ride can in fact only have one horse. If this was a mistake, then leave your forms alone but change the model so that a ride has_many :horses and accepts_nested_attributes_for :horses
I am now saving relationships correctly with below code (with a one caveat). Thanks to previous posters for getting me headed in the right direction!
Also Formtastic doc link: http://rdoc.info/github/justinfrench/formtastic/Formtastic/Inputs/SelectInput
The caveat: I cannot figure out how to select an existing horse with form select if I do not want to add a new horse (_ride_fields.html.haml). Adding new horse works fine.
When I attempt with current commented code I get error:
undefined method ride_id for Ride
I am not sure if this a formtastic problem, model related, or controller. I will post this as a separate question if I do not figure it out.
I realized in my original posting that I should not have foreign keys (eg ride_id) saved to 'entries' table because they are saved to the related tables (rides) in entry_id field.
entries controller (partial):
class EntriesController < ApplicationController
before_filter :set_horses, :except => [:destroy, :index]
def new
#c_user=current_user[:id]
#user=current_user
#entry = current_user.entries.new
#horses = current_user.horses
end
def create
#entry = current_user.entries.new(entry_params)
respond_to do |format|
if #entry.save
format.html { redirect_to #entry, notice: 'Entry was successfully created.' }
format.json { render :show, status: :created, location: #entry }
else
format.html { render :new }
format.json { render json: #entry.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_horses
if current_user.admin?
#horses=Horse.all
else
#horses = current_user.horses
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def entry_params
params.require(:entry).permit(:show_date, rides_attributes: [:id, :test, :_destroy, horse_attributes: [:name, :id]] )
end
end
entry.rb:
class Entry < ActiveRecord::Base
belongs_to :user
has_many :rides, :dependent => :destroy
has_many :horses, :through => :rides, :dependent => :destroy
has_many :riders, :through => :rides, :dependent => :destroy
accepts_nested_attributes_for :rides, :reject_if => lambda { |a| a[:test].blank? }, :allow_destroy => true
accepts_nested_attributes_for :horses, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
accepts_nested_attributes_for :riders, :allow_destroy => true
validates_presence_of :show_date
end
ride.rb:
class Ride < ActiveRecord::Base
belongs_to :entry, inverse_of: :entry
belongs_to :user, inverse_of: :user
has_one :horse
has_one :rider
accepts_nested_attributes_for :horse
end
horse.rb:
class Horse < ActiveRecord::Base
belongs_to :ride, :dependent => :destroy
belongs_to :user, :dependent => :destroy
end
_form.html.haml
= semantic_form_for #entry do |f|
= f.inputs do
= f.input :show_date, :as => :select, :collection => ['2014/08/03', '2014/09/14', '2014/10/26', '2014/11/15']
%h3 Rides
#rides
= f.semantic_fields_for :rides do |ride|
= render 'ride_fields', :f => ride
.links
= link_to_add_association 'add ride', f, :rides
= f.actions do
= f.action :submit
_ride_fields.html.haml
.nested-fields
= f.inputs do
= f.label :test, "Test"
= f.input :test, :as => :select, :collection => [['Intro A', 'Intro A'], ['Intro B', 'Intro B'], ['Intro C', 'Intro C']]
= if !#horses.empty?
-# both of next 2 lines give error: undefined method ride_id for <Ride:0x00000008cc3370>
-#= f.input :horse, :as => :select, :collection => #horses
-#= f.input :horse, :as => :select, :member_label => :name
= f.semantic_fields_for :horse do |horse|
= render 'horse_fields', :f => horse
.links
= link_to_add_association 'add new horse', f, :horse
_horse_fields.html.haml
.nested-fields
= f.inputs do
= f.input :name
I am trying to build a multitenant app using rails 4 and devise. The design I am attempting is that an account has one owner(primary user) and has many users. I have an account being added along with the nested form adding the user. I'm not sure if I have issue with the schema I'm attempting to populate or if I am missing a step that would allow me to add an account and user at the same time, with the account record being populated with the owner_id (primary user) and the user being populated with the account_id.
class Account < ActiveRecord::Base
cattr_accessor :current_id
has_many :users
has_one :owner, class_name: 'User'
validates :owner, presence: true
accepts_nested_attributes_for :owner
end
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :account
end
class AccountsController < ApplicationController
def new
#account = Account.new
#account.build_owner
end
def create
#account = Account.new(account_params)
if #account.save
redirect_to root_path, notice: 'Successfully Created Account!'
else
render action: 'new'
end
end
private
def account_params
params.require(:account).permit(:subdomain, owner_attributes: [:email, :password, :password_confirmation])
end
end
Views/Accounts/new.html.erb
<div class="col-md-6 col-md-offset-3 panel panel-default">
<div class="panel-body">
<h2>Create an Account</h2>
<%= form_for #account do |f| %>
<%= f.fields_for :owner do |o| %>
<%= form_group_for o, :email do %>
<%= o.text_field :email, class: 'form-control' %>
<% end %>
<%= form_group_for o, :password do %>
<%= o.password_field :password, class: 'form-control' %>
<% end %>
<%= form_group_for o, :password_confirmation do %>
<%= o.password_field :password_confirmation, class: 'form-control' %>
<% end %>
<% end %>
<%= form_group_for f, :name, opts= {:label => "Company Name"} do %>
<%= f.text_field :name, class: 'form-control' %>
<% end %>
<%= f.submit class: 'btn btn-primary' %>
<% end %>
</div>
</div>
App/Helper/Form_Helper (view call this)
module FormHelper
def errors_for(form, field)
content_tag(:p, form.object.errors[field].try(:first), class: 'help-block')
end
def form_group_for(form, field, opts={}, &block)
if opts.has_key?(:label)
label = opts.fetch(:label)
else
label = field.to_s
end
has_errors = form.object.errors[field].present?
content_tag :div, class: "form-group #{'has-error' if has_errors}" do
concat form.label(label, class: 'control-label')
concat capture(&block)
concat errors_for(form, field)
end
end
end
DB/schema.rb
ActiveRecord::Schema.define(version: 20140629124546) do
create_table "accounts", force: true do |t|
t.string "name"
t.integer "owner_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "clients", force: true do |t|
t.string "name", null: false
t.text "address"
t.integer "account_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "clients", ["account_id"], name: "index_clients_on_account_id"
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.integer "account_id"
end
add_index "users", ["account_id"], name: "index_users_on_account_id"
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
Currently the design creates both the account and user records. The user record is populated with the account_id, but the account_id isn't populated with the owner_id (user_id).
This is likely in your associations, which are currently incomplete and a bit inaccurate.
If a model's attribute holds a foreign key, like the owner_id attribute on your Account model, then it belongs_to that model it is referencing. Think of it like a cattle brand. If you have the ids of other models on you, you belong to those models. You current have a has_one where you need a belongs_to.
You will also need to set up the inverse association, which is currently lacking in your user model.
Assuming you actually will only ever want a user to be associated with one account (as opposed to a user being on more than one account), you could rearrange your associations like this:
#models/account.rb
class Account < ActiveRecord::Base
has_many :users
belongs_to :owner, class_name: 'User'
accepts_nested_attributes_for :owner
end
#models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :account
has_one :owned_account, class_name: 'Account', foreign_key: 'owner_id'
end
Proper association setup will hopefully fix your issue.
I've been looking at my code for some time now and can't work out where the errors are with Devise. I've added a few additional lines to the Sign Up view and changed everything as described in the Devise Readme, but the additional fields are not showing up, only the usual Email, Password and Confirm Password fields are. My users are called Knockers, in case anyone was wondering!
Here is my views page (registrations\new.html.erb):
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.text_field :first_name %></div>
<div><%= f.text_field :last_name %></div>
<div><%= f.text_field :username %></div>
<div><%= f.text_field :gender %></div>
<div><%= f.date_field :dob %></div>
<div><%= f.label :email %><br />
<%= f.email_field :email, :autofocus => true %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<% if knocker_signed_in? %>
Signed in as <%= current_knocker.name %>. Not you?
<%= link_to "Sign out", destroy_knocker_session_path,:method => :delete %>
<% else %>
<%= link_to "Sign up", new_knocker_registration_path %> or
<%= link_to "Sign in", new_knocker_session_path %>
<%= link_to "Sign in with Facebook", knocker_omniauth_authorize_path(:facebook) %>
<% end %>
<% if knocker_signed_in? %>
Signed in as <%= current_knocker.name %>. Not you?
<%= link_to "Sign out", destroy_knocker_session_path,:method => :delete %>
<% else %>
<%= link_to "Sign up", new_knocker_registration_path %> or
<%= link_to "Sign in", new_knocker_session_path %>
<%= link_to "Sign in with Twitter", knocker_omniauth_authorize_path(:twitter) %>
<% end %>
<% if knocker_signed_in? %>
Signed in as <%= current_knocker.name %>. Not you?
<%= link_to "Sign out", destroy_knocker_session_path,:method => :delete %>
<% else %>
<%= link_to "Sign up", new_knocker_registration_path %> or
<%= link_to "Sign in", new_knocker_session_path %>
<%= link_to "Sign in with Google", knocker_omniauth_authorize_path(:google_oauth2) %>
<% end %>
<%= render "knockers/shared/links" %>
My model page (\knocker.rb)
Class Knocker < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :omniauth_providers => [:facebook, :twitter, :google_oauth2]
before_save { self.username = username.downcase }
validates :first_name, presence: true,
length: { maximum: 25 }
validates :last_name, presence: true,
length: { maximum: 25 }
VALID_USERNAME_REGEX = /\A[\w+\-._]+\z/i
validates :username, presence: true,
length: { maximum: 20 },
format: { with: VALID_USERNAME_REGEX },
uniqueness: { case_sensitive: false }
validates :email, presence: true
validates :password, presence: true
validates :dob, presence: true
validates :gender, presence: true
validates :postcode, presence: true
def self.find_for_facebook_oauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do |knocker|
knocker.provider = auth.provider
knocker.uid = auth.uid
knocker.email = auth.info.email
knocker.password = Devise.friendly_token[0,20]
#knocker.first_name = auth.info.name # assuming the user model has a name
#knocker.image = auth.info.image # assuming the user model has an image
end
end
def self.find_for_twitter_oauth(auth, signed_in_resource=nil)
knocker = Knocker.where(:provider => auth.provider, :uid => auth.uid).first
if knocker
return knocker
else
registered_knocker = Knocker.where(:email => auth.uid + "#twitter.com").first
if registered_knocker
return registered_knocker
else
knocker = Knocker.create(full_name:auth.extra.raw_info.name,
provider:auth.provider,
uid:auth.uid,
email:auth.uid+"#twitter.com",
password:Devise.friendly_token[0,20],
username:auth.info.nickname,
about:auth.info.description )
end
end
end
def self.find_for_google_oauth2(access_token, signed_in_resource=nil)
data = access_token.info
knocker = Knocker.where(:provider => access_token.provider, :uid => access_token.uid ).first
if knocker
return knocker
else
registered_knocker = Knocker.where(:email => access_token.info.email).first
if registered_knocker
return registered_knocker
else
knocker = Knocker.create(first_name: data["first_name"],
last_name: data["last_name"],
provider:access_token.provider,
email: data["email"],
uid: access_token.uid ,
password: Devise.friendly_token[0,20],
gender: data["gender"],
dob: data["birthday"]
)
end
end
end
def self.new_with_session(params, session)
super.tap do |knocker|
if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
knocker.email = data["email"] if knocker.email.blank?
end
end
end
def name
first_name + " " + last_name
end
end
My database migration:
class DeviseCreateKnockers < ActiveRecord::Migration
def change
create_table(:knockers) do |t|
t.string :first_name, :null => false
t.string :last_name, :null => false
t.string :username, :null => false
t.string :town
t.string :postcode
t.float :latitude
t.float :longitude
t.date :dob, :null => false
t.text :about
t.string :gender, :null => false
t.string :nationality
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
## Omniauth data
t.string :provider
t.string :uid
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
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
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts
t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps
end
add_index :knockers, :email, :unique => true
add_index :knockers, :reset_password_token, :unique => true
add_index :knockers, :username, :unique => true
add_index :knockers, :latitude
add_index :knockers, :longitude
add_index :knockers, :dob
# add_index :knockers, :confirmation_token, :unique => true
# add_index :knockers, :unlock_token, :unique => true
end
end
and finally my Application Controller:
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
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :first_name, :last_name, :gender, :dob, :email, :password, :password_confirmation) }
end
end
Any help would be greatly appreciated. I've looked on here through a few problems, but most of them just seem to be in getting the wrong field type... can't see what the problem is here unless it's something to do with a badly implemented OAuth problem.
Rename the knockers folder under application_name/app/views directory to devise.
While generating the views you by mistake generated them as rails generate devise:views knockers instead of rails generate devise:views.
You use rails generate devise:views knockers to generate views if you have multiple devise models and you need different views(customizations) for them.
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