Rails: add relationship with other table for Devise user - ruby-on-rails

I want to add an input to my Devise user sign_up form in order to add a team name. I created a specific table for Teams and I created a relationship: Users belong to Team. Team has many users.
The problem is I need to add a Team_id when submiting the sign_up form. How can I save the value of the Team input in the register form to the Team table and get the Id in order to save it to the team_id entry in Devise User table?
My Sign Up form:
<div class="container_index">
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
</div>
<div class="field">
<%= f.label :team %><br />
<%= f.text_field :team %>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
</div>
My user schema:
create_table "users", force: :cascade 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.integer "team_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["team_id"], name: "index_users_on_team_id"
end
My application controller:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
skip_before_action :verify_authenticity_token
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit(:name, :email, :password, :team) }
devise_parameter_sanitizer.permit(:account_update) { |u| u.permit(:name, :email, :password, :current_password, :team) }
end
Thank you.

Related

Rails 5 - Nested Model Form Not Saving Child Model Attributes

I've been at this problem for a couple weeks now on and off.
Currently I have a User model, Employee model and an Employee_Contact model. The User model was generated using Devise. After the User is logged in they can go to their User Dashboard and create an Employee using a nested form. I am having an issue where the child model Employee_Contact is not saving into the database.
Schema:
create_table "employee_contacts", force: :cascade do |t|
t.string "street"
t.string "city"
t.string "state"
t.string "zip"
t.string "phone_num"
t.string "alt_phone_num"
t.string "email"
t.string "emergency_contact_first_name"
t.string "emergency_contact_last_name"
t.string "emergency_contact_num"
t.integer "user_id"
t.integer "employee_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["employee_id"], name: "index_employee_contacts_on_employee_id"
t.index ["user_id"], name: "index_employee_contacts_on_user_id"
end
create_table "employees", force: :cascade do |t|
t.string "first_name"
t.string "middle"
t.string "last_name"
t.string "sex"
t.string "race"
t.date "birthdate"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "employee_contact_id"
t.index ["user_id"], name: "index_employees_on_user_id"
end
create_table "users", force: :cascade 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.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name:
"index_users_on_reset_password_token", unique: true
end
end
These are my models:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :employees, :dependent => :destroy
end
class Employee < ApplicationRecord
belongs_to :user
has_one :employee_contact, inverse_of: :employee, autosave: true
accepts_nested_attributes_for :employee_contact, allow_destroy: true
end
class EmployeeContact < Employee
belongs_to :employee, inverse_of: :employee_contact
end
My Employee Controller:
class EmployeesController < ApplicationController
before_action :authenticate_user!
def index
#employees = Employee.all
end
def new
#employee = Employee.new
end
def create
#employee = current_user.employees.create(employee_params)
if #employee.save!
redirect_to root_path
else
render :new, status: :unprocessable_entity
end
end
private
def employee_params
params.require(:employee).permit(:first_name, :middle, :last_name,
:sex, :race, :birthdate, employee_contact: [:id, :street, :city,
:state, :zip, :phone_num, :email, :alt_phone_num,
:emergency_contact_first_name, :emergency_contact_last_name,
:emergency_contact_num])
end
end
My View Form:
<%= form_with(model: #employee, local: true) do |form| %>
<h3>Employee Profile Information</h3>
<%= form.label :first_name %><br />
<%= form.text_field :first_name %><br />
<%= form.label :middle %><br />
<%= form.text_field :middle %><br />
<%= form.label :last_name %><br />
<%= form.text_field :last_name %><br />
<%= form.label :sex %><br />
<%= form.text_field :sex %><br />
<%= form.label :race %><br />
<%= form.text_field :race %><br />
<%= form.label :birthdate %><br />
<%= form.date_field :birthdate %><br />
<h3>Employee Contact Information</h3><br />
<%= form.fields_for :employee_contacts do |builder| %>
<%= builder.label :street %><br />
<%= builder.text_area :street %><br />
<%= builder.label :city %><br />
<%= builder.text_area :city %><br />
<%= builder.label :street %><br />
<%= builder.text_area :street %><br />
<%= builder.label :state %><br />
<%= builder.text_area :state %><br />
<%= builder.label :zip %><br />
<%= builder.text_area :zip %><br />
<%= builder.label :phone_num %><br />
<%= builder.text_area :phone_num %><br />
<%= builder.label :alt_phone_num %><br />
<%= builder.text_area :alt_phone_num %><br />
<%= builder.label :email %><br />
<%= builder.text_area :email %><br />
<%= builder.label :emergency_contact_first_name %><br />
<%= builder.text_area :emergency_contact_first_name %><br />
<%= builder.label :emergency_contact_last_name %><br />
<%= builder.text_area :emergency_contact_last_name %><br />
<%= builder.label :emergency_contact_num %><br />
<%= builder.text_area :emergency_contact_num %><br />
<% end %>
<%= form.submit "Add", class: 'btn btn-primary' %><br />
<% end %>
When I get submit the form to create a new employee this is what I get in my console parameters:
Processing by EmployeesController#create as HTML
Parameters:{"utf8"=>"✓","authenticity_token"=>"IgYzybxM8+M8jZ8NJgYKZ+Zhqr07kcV1e0QyWf> uY8hQLyBY844jfOlLNl65F/2RRr4TTW0F1MeSmDzVzBsXOjg==", "employee"=>
{"first_name"=>"Firt Nam", "middle"=>"kk", "last_name"=>"jak", "sex"=>"dfkj", "race"=>"jkadflj", "birthdate"=>"2011-01-01", "employee_contacts"=>{"street"=>"afdjkljadfkl", "city"=>"jadklfjakldfj", "state"=>"fadjlkdf", "zip"=>"32787", "phone_num"=>"567567567", "alt_phone_num"=>"57875875875", "email"=>"dajkjdlkfj#jkj.com", "emergency_contact_first_name"=>"adfjkladjf", "emergency_contact_last_name"=>"adfjkaldf", "emergency_contact_num"=>"784339793"}}, "commit"=>"Add"}
Unpermitted parameter: :employee_contacts
And so it saves the Employee but not anything associated with their contact information. If I run Employee.last in the Rails console I get a nil value for employee_contact_id. If I try and use the Rails Console to look up Employee_Contact.last or Employee_Contact.all I get an 'unable to autoload constant Employee_Contact, expected employee_contact.rb to define it'.
UPDATE
I changed a few things thanks to Anton.
My Employee Contact model now inherits from ApplicationRecord:
class EmployeeContact < ApplicationRecord
belongs_to :employee, inverse_of: :employee_contact
end
I changed the view form in the employee_contact loop from plural to singular:
<%= form.fields_for :employee_contact do |builder| %>
I added a build method in Employee#New
def new
#employee = Employee.new
#employee.build_employee_contact
end
And edited Employee#Create
def create
#employee = current_user.employees.create(employee_params)
if #employee.valid?
redirect_to root_path
else
render :new, status: :unprocessable_entity
end
end
This is now saving an Employee Contact. Here are the results from the console:
#<EmployeeContact id: 1, street: "dafjkafdjl", city: "adjfklajdk", state: "dfjkljalkdfjioad", zip: "dafjadlkfjkajdkl", phone_num: "adf", alt_phone_num: "871274892174", email: "dafnajdklj#jkklda.com", emergency_contact_first_name: "ajdfjalkj", emergency_contact_last_name: "fjadkljdfkl", emergency_contact_num: "11287244", user_id: nil, employee_id: 1, created_at: "2017-10-03 19:01:55", updated_at: "2017-10-03 19:01:55">
Employee id: 1, first_name: "dafad", middle: "dfad", last_name: "dafd", sex: "adfd", race: "dfad", birthdate: "1210-01-01", user_id: 1, created_at: "2017-10-03 19:01:55", updated_at: "2017-10-03 19:01:55", employee_contact_id: nil>
The Employee model is still getting an Employee_Contact_Id: nil value. However, the Employee Contact model is getting the correct Employee_Id attribute.
SOLVED
So I'm going to leave it at with what I have posted in the Update. There is no need for my Employee model to have an Employee_Contact_Id attribute. When I create a new Employee the Contact correctly maps to that Employee currently.
Please set the EmployeeContact to inherit from ApplicationRecord, not Employee.
In the new action build the employee contact for the nested form from the employee.
I would suggest to remove the foreign key from the has_one association.
The employee_id on the employee_contact is enough.

Devise not allowing sign-in

I am installing devise on a Rail 5 application. I'm just doing out-of-the-box. No fancy installation other than fixing up the generated views.
Devise is not letting my users log in to the application. I first encountered the issue when trying to create a new user. I got the error:
1 error prohibited this user from being saved:
Email can't be blank
But my email is not blank. So I tried created a user from rails c. The user stuck. It shows up in my database. But when I try to sign in through devise, I get this error:
Invalid Username or password.
It is valid. I don't know what is going on. Here is my schema:
create_table "users", force: :cascade 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", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
Here is the new user view:
<div class="row">
<div class="col-md-4 col-md-push-4 col-sm-6 col-sm-push-3 col-xs-10 col-xs-push-1">
<h3>Sign up</h3>
<br />
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="form-group">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off", class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off", class: 'form-control' %>
</div>
<div class="form-group">
<%= f.submit "Sign up", class: 'btn btn-primary' %>
</div>
<% end %>
<%= render "devise/shared/links" %>
</div>
</div>
Model:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
I can definitely confirm there is one user in my database. I don't know what's going on. As far as I can tell, I did nothing out of the ordinary setting this up. Help!

My devise User model custom field username always nil. I have tried all the other solutions on stack overflow

My application controller file
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_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) {|u| u.permit(:username, :email, :password, :password_confirmation, :remember_me)}
devise_parameter_sanitizer.permit(:sign_in) {|u| u.permit(:username, :email, :password, :password_confirmation, :remember_me)}
devise_parameter_sanitizer.permit(:account_update) {|u| u.permit(:email, :password, :password_confirmation, :remember_me)}
end
end
My routes.rb file
Rails.application.routes.draw do
devise_for :users
root 'pages#index'
get 'home' => 'pages#home'
get 'profile' => 'pages#profile'
get 'explore' => 'pages#explore'
end
My migration files
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## 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 null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
My add username column migration
class AddUsernameToUsers < ActiveRecord::Migration
def change
add_column :users, :username, :string
add_index :users, :username, unique: true
end
end
My views/devise/registrations/new.html.erb
<%= bootstrap_devise_error_messages! %>
<div class="panel panel-default devise-bs">
<div class="panel-heading">
<h4><%= t('.sign_up', default: 'Sign up') %></h4>
</div>
<div class="panel-body">
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { role: 'form' }) do |f| %>
<div class="form-group">
<%= f.label :username %>
<%= f.text_field :email, autofocus: true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
</div>
<%= f.submit t('.sign_up', default: 'Sign up'), class: 'btn btn-primary' %>
<% end %>
</div>
</div>
<%= render 'devise/shared/links' %>
So even after using strong parameters when the usernames being added through browser are not reflected back in the database.
It gives this result
irb(main):001:0> u = User.all
User Load (20.0ms) SELECT "users".* FROM "users"
=> #<ActiveRecord::Relation [#<User id: 1, email: "testuser#test.com", created_at: "2017-07-05 19:42:19", updated_at: "2017-07-05 21:11:38", username: nil>, #<User id: 2, email: "ajha#test.com", created_at: "2017-07-06 08:45:18", updated_at: "2017-07-06 08:45:18", username: nil>, #<User id: 3, email: "akasd#test.com", created_at: "2017-07-06 08:56:15", updated_at: "2017-07-06 08:56:15", username: nil>, #<User id: 4, email: "rcontest#test.com", created_at: "2017-07-06 09:23:55", updated_at: "2017-07-06 09:23:55", username: nil>]>
Any help will be appreciated. Also tell me if you need to see any other files.
My devise User model custom field username always nil
Because you don't have it in the form. Change
<div class="form-group">
<%= f.label :username %>
<%= f.text_field :email, autofocus: true, class: 'form-control' %>
</div>
to this
<div class="form-group">
<%= f.label :username %>
<%= f.text_field :username, autofocus: true, class: 'form-control' %>
</div>
you did not specify username attribute in the form
add username in the form
<div class="form-group">
<%= f.label :username %>
<%= f.text_field :username, autofocus: true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
</div>

Rails many to many model with select in the view

The logic in the exercise is create a Bill where a Bill have a list of Products with an amount of them.
I have the next 3 models:
Bill
Product
BillItem (This is the intermediate model between Bill and Product for the many to many relationship)
Schema for more clarity:
create_table "bill_items", force: :cascade do |t|
t.integer "amount"
t.integer "product_id"
t.integer "bill_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["bill_id"], name: "index_bill_items_on_bill_id"
t.index ["product_id"], name: "index_bill_items_on_product_id"
end
create_table "bills", force: :cascade do |t|
t.string "user_name"
t.string "dni"
t.date "expiration"
t.float "sub_total"
t.float "grand_total"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "products", force: :cascade do |t|
t.string "name"
t.string "description"
t.float "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
First i have a list of created products in my database.
For my BillController i have a _form.html.erb where i want be capable to create dynamic selects for choose a product and set a amount.
My view is the next:
<%= form_for bill do |f| %>
<div>
<%= f.label :user_name %>
<%= f.text_field :user_name %>
</div>
<div>
<%= f.label :dni %>
<%= f.text_field :dni %>
</div>
<div>
<%= f.label :product %>
<%= f.collection_select :product_ids, Product.all, :id, :name %>
</div>
# Here i should add more selects if the user want to add more products.
<div><%= f.submit %></div>
<% end %>
My problem or my question is: how to "groupe" the ids of the products and the amount of them. And the another question is, i can create the other selects dynamically with JS?
You need to be adding multiple BillItem to your form to account for the amount and the product. This is done through accepts_nested_attributes_for on the model. For example:
class Bill < ActiveRecord::Base
has_many :bill_items
accepts_nested_attributes_for :bill_items
end
Initialize a BillItem on the Bill in your controller:
class BillsController < ActionController::Base
def new
#bill = Bill.new
#bill.bill_items.build
end
end
Then in your form, use the fields_for helper to create sub-forms:
<%= form_for #bill do |f| %>
<div>
<%= f.label :user_name %>
<%= f.text_field :user_name %>
</div>
<div>
<%= f.label :dni %>
<%= f.text_field :dni %>
</div>
<%= f.fields_for :bill_items do |f| %>
<div>
<%= f.label :product %>
<%= f.collection_select :product_id, Product.all, :id, :name %>
</div>
<div>
<%= f.label :amount %>
<%= f.number_field :amount %>
</div>
<% end %>
<%= f.submit %></div>
<% end %>
And yes, you can use javascript to create new nested forms.

Name Method Error, undefined method

I am getting this error message when I try to load my sign up page with devise. I have a name input in my migrate file, so I am not sure where the no method error is coming from.
Error:
NoMethodError in Devise::Registrations#new
Showing /Users/ericpark/rails_projects/bloccit-2/app/views/devise/registrations/new.html.erb where line #9 raised:
undefined method `name' for #
For page new.html.erb
<h2>Sign up</h2>
<div class="row">
<div class="col-md-8">
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, autofocus: true, class: 'form-control', placeholder: "Enter name" %>
</div>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control', placeholder: "Enter email" %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control', placeholder: "Enter password" %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control', placeholder: "Enter password confirmation" %>
</div>
<div class="form-group">
<%= f.submit "Sign up", class: 'btn btn-success' %>
</div>
<div class="form-group">
<%= render "devise/shared/links" %>
</div>
<% end %>
</div>
</div>
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_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :name
end
end
Migrate File for Users:
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :name #Added by Bloc.io
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## 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 :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
For some reason, that part of your migration is being ignored. So lets build a new migration to add name to the users table.
In console, run:
rails g migration addNameToUsers name:string
then run
rake db:migrate
Are you able to create users with names from the rails console? If you can't you probably need to reset your database (rake db:reset).

Resources