I have a little app that is using devise and apartment gems.
I have User(devise) who has one organization(tenant_name).
The organization has one :owner, class_name 'user'
I want to use the Devise registration form to also create the tenant and assign to the admin.
I think I have read that many tutorials on devise apartment / devise custom controllers / devise nested attributes that I have confused myself.
Registrations form
app/views/devise/registrations/new.html.erb
<div class="row">
<div class="col-lg-4 col-md-6 ml-auto mr-auto">
<h1 class="text-center">Sign Up</h1>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render partial: 'devise/shared/error_messages', resource: resource %>
<div class="form-group">
<%= f.email_field :email, autofocus: false, class: 'form-control', placeholder: "Email Address" %>
</div>
<div class="form-group">
<%= f.simple_fields_for :organizations do |o| %>
<%= o.input :name, placeholder: "Organization Name", warning: "Cant Be Changed", label: false %>
<% end %>
</div>
<div class="form-group">
<%= f.password_field :password, autocomplete: "off", class: 'form-control', placeholder: 'Password' %>
</div>
<div class="form-group">
<%= f.password_field :password_confirmation, autocomplete: "off", class: 'form-control', placeholder: 'Confirm Password' %>
</div>
<div class="form-group">
<%= f.submit "Sign up", class: "btn btn-primary btn-block btn-lg" %>
</div>
<% end %>
<div class="text-center">
<%= render "devise/shared/links" %>
</div>
</div>
</div>
User Model
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_one :organization, dependent: :destroy
after_create :init_organization
accepts_nested_attributes_for :organization
private
def init_organization
self.create_organization!
end
end
Organization Model
class Organization < ApplicationRecord
has_one :owner, class_name: 'User'
has_many :organizations_users
has_many :users, through: :organizations_users
has_many :clients
after_create :create_tenant
def tenant_name
"#{self.id}"
end
private
def create_tenant
Apartment::Tenant.create(self.tenant_name)
end
end
I know that I need to alter my create method on my devise controller so i generated devise custom controllers with from here
rails generate devise:controllers users
and added the custom sanitizers
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
# GET /resource/sign_up
# def new
# super
# end
# POST /resource
def create
super
end
# GET /resource/edit
# def edit
# super
# end
# PUT /resource
# def update
# super
# end
# DELETE /resource
# def destroy
# super
# end
# GET /resource/cancel
# Forces the session data which is usually expired after sign
# in to be expired now. This is useful if the user wants to
# cancel oauth signing in/up in the middle of the process,
# removing all OAuth session data.
# def cancel
# super
# end
# protected
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:email, organizations: [:name]])
end
# If you have extra params to permit, append them to the sanitizer.
# def configure_account_update_params
# devise_parameter_sanitizer.permit(:account_update, keys: [:attribute])
# end
# The path used after sign up.
# def after_sign_up_path_for(resource)
# super(resource)
# end
# The path used after sign up for inactive accounts.
# def after_inactive_sign_up_path_for(resource)
# super(resource)
# end
end
schema
ActiveRecord::Schema.define(version: 2019_05_12_083957) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
enable_extension "uuid-ossp"
create_table "Organizations_Users", id: false, force: :cascade do |t|
t.uuid "Organization_id", null: false
t.uuid "User_id", null: false
end
create_table "clients", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "name"
t.uuid "organization_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["organization_id"], name: "index_clients_on_organization_id"
end
create_table "equipment", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "name"
t.uuid "site_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["site_id"], name: "index_equipment_on_site_id"
end
create_table "organizations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.uuid "user", null: false
end
create_table "sites", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "name"
t.uuid "client_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["client_id"], name: "index_sites_on_client_id"
end
create_table "users", id: :uuid, default: -> { "gen_random_uuid()" }, 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.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
add_foreign_key "clients", "organizations"
add_foreign_key "equipment", "sites"
add_foreign_key "sites", "clients"
end
when i go through the sign up process i get unknown attribute 'organizations' for User.
Update:
I added two new migration to add reference to user on the organization, and organization to the user.
I did this to create the association for the owner, should i have called the reference owner
class AddUserToOrganization < ActiveRecord::Migration[5.2]
def change
add_reference :organizations, :user, type: :uuid, null: false, index: true, foreign_key: true
end
end
class AddOrganizationToUser < ActiveRecord::Migration[5.2]
def change
add_reference :users, :organization, type: :uuid, null: false, index: true, foreign_key: true
end
end
My Schema now looks like so:
ActiveRecord::Schema.define(version: 2019_05_13_223120) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
enable_extension "uuid-ossp"
create_table "Organizations_Users", id: false, force: :cascade do |t|
t.uuid "Organization_id", null: false
t.uuid "User_id", null: false
end
create_table "clients", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "name"
t.uuid "organization_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["organization_id"], name: "index_clients_on_organization_id"
end
create_table "equipment", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "name"
t.uuid "site_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["site_id"], name: "index_equipment_on_site_id"
end
create_table "organizations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.uuid "user_id", null: false
t.index ["user_id"], name: "index_organizations_on_user_id"
end
create_table "sites", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "name"
t.uuid "client_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["client_id"], name: "index_sites_on_client_id"
end
create_table "users", id: :uuid, default: -> { "gen_random_uuid()" }, 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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.uuid "organization_id", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["organization_id"], name: "index_users_on_organization_id"
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_foreign_key "clients", "organizations"
add_foreign_key "equipment", "sites"
add_foreign_key "organizations", "users"
add_foreign_key "sites", "clients"
add_foreign_key "users", "organizations"
end
I followed the direction from to change my user/ registrations controller to :
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
def new
super
#organization = Organization.new
end
# POST /resource
def create
super
end
# GET /resource/edit
# def edit
# super
# end
# PUT /resource
# def update
# super
# end
# DELETE /resource
# def destroy
# super
# end
# GET /resource/cancel
# Forces the session data which is usually expired after sign
# in to be expired now. This is useful if the user wants to
# cancel oauth signing in/up in the middle of the process,
# removing all OAuth session data.
# def cancel
# super
# end
# protected
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:email, organizations: [:name]])
end
# If you have extra params to permit, append them to the sanitizer.
# def configure_account_update_params
# devise_parameter_sanitizer.permit(:account_update, keys: [:attribute])
# end
# The path used after sign up.
# def after_sign_up_path_for(resource)
# super(resource)
# end
# The path used after sign up for inactive accounts.
# def after_inactive_sign_up_path_for(resource)
# super(resource)
# end
end
and my form now
<%= simple_form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => {:class => 'form-horizontal' }) do |f| %>
<%= render partial: 'devise/shared/error_messages', resource: resource %>
<%= f.input :email, autofocus: false, class: 'form-control', placeholder: "Email Address", label: false %>
<%= f.simple_fields_for :organization do |o| %>
<%= o.input :name, placeholder: "Organization Name", warning: "Cant Be Changed", label: false %>
<% end %>
<%= f.input :password, autocomplete: "off", class: 'form-control', placeholder: 'Password', label: false %>
<%= f.input :password_confirmation, autocomplete: "off", class: 'form-control', placeholder: 'Confirm Password', label: false %>
<%= f.button :submit, "Sign up", class: "btn btn-primary btn-block btn-lg" %>
<% end %>
my problem now is that i cannot see the organization name field in the view of the form.
In has_one relation you should use the singular form:
<div class="form-group">
<%= f.simple_fields_for :organization do |o| %>
<%= o.input :name, placeholder: "Organization Name", warning: "Cant Be Changed", label: false %>
<% end %>
</div>
I think the rest of your code should work as is!
Edit: how to instantiate a new org
You indicated that the form is empty, that's because there is no org instance. Do the following in your user controller:
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
GET /resource/sign_up
def new
super
#user.organization = Organization.new
end
# POST /resource
def create
super
end
end
Related
I'm trying to add a nested attributes to my signup form (generated by devise), but it didn't work.
To give a brief explanation:
A user has many locations, and each location has a label name (home,eg.) and an address.
What I wanted to do here is to allow new user to register their location(nested attributes) in the signup form.
In other words, to create a new location, which is associated with the new user.
*I have already set up strong params and controllers, by referring to stackoverflow threads and other sources.
Here's my codes:
User Model
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :locations, dependent: :destroy
validates :first_name, presence: true
validates :last_name, presence: true
validates :email, presence: true
accepts_nested_attributes_for :locations
end
Location Model
class Location < ApplicationRecord
belongs_to :user
validates :label, presence: true
validates :address, presence: true
geocoded_by :address
after_validation :geocode, if: :will_save_change_to_address?
end
My Signup Form
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<div class="form-inputs">
..........
<%= f.simple_fields_for :location do |p| %>
<%= p.input :address %>
<%= p.input :label, collection: ['Home', 'Work'] %>
<% end %>
<%= f.button :submit, "Sign up", class: "btn btn-long" %>
</div>
<% end %>
Registration Controllers (Devise)
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
def new
build_resource({})
self.resource.locations.build
respond_with self.resource
end
protected
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:email, :first_name, :last_name, :password, :photo, locations_attributes: [:label, :address]])
end
end
Application Controller
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_user!
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:email, :first_name, :last_name, :password, :photo, locations_attributes: [:label, :address]])
end
end
DB Schema
ActiveRecord::Schema.define(version: 2019_08_30_001623) do
create_table "locations", force: :cascade do |t|
t.string "label"
t.text "address"
t.float "latitude"
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.float "longitude"
t.index ["user_id"], name: "index_locations_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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "first_name"
t.string "last_name"
t.boolean "admin"
t.text "preference", default: "no preference"
t.integer "default_location"
t.integer "radius"
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
Please let me know if you have any additional question or if you need anymore info.
Appreciate all your helps
I am trying to sign up using devise for an application I am making. The form submit action is sending the correct params but I am failing on one presence validation. That presence validation is a checkbox field where a user selects on sign up whether they are single or not.
Here is the code for views/devise/registrations/new.html.erb
<div class="radio">
<%= f.label :relationship_status%><br />
<%= radio_button_tag(:relationship_status, "single") %>
<%= label_tag(:single, "Single") %>
<%= radio_button_tag(:relationship_status, "relationship") %>
<%= label_tag(:relationship, "In a relationship") %>
</div>
Here is the ApplicationController where I specify the params to be passed aside from the defaults provided by devise:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name,
:username, :birthday,
:relationship_status])
end
end
Here is my user model where I set basic presence validators
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
validates :name, :email, :username,
:birthday,:relationship_status, presence: true
end
Finally, here is an image of clicking Sign Up once I fill the form:
ActiveRecord::Schema.define(version: 2019_06_05_024141) do
create_table "users", force: :cascade do |t|
t.string "name", null: false
t.string "username", null: false
t.datetime "birthday", null: false
t.string "relationship_status", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
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.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
As you can see in the picture relationship_status is clearly set to single. Yet I keep getting an error saying that it can't be blank. I am stumped and some help would be appreciated. Thank you.
could you try with this.
<div class="radio">
<%= f.label :relationship_status%><br />
<%= f.radio_button(:relationship_status, "single") %>
<%= label_tag(:single, "Single") %>
<%= f.radio_button(:relationship_status, "relationship") %>
<%= label_tag(:relationship, "In a relationship") %>
</div>
I don't know how this was fixed, but my approach was to confirm with byebug. While doing so, I executed rails generate devise:controllers [scope] and modified my route.rb with the following:
Rails.application.routes.draw do
devise_for :users, controllers: {
sessions: 'users/sessions'
}
end
This fixed it.
Have a recipient and sender, both of the same class(Message) for a messaging system in rails. Want to set the params for both i.e. if user creates a message sender by default is the user_id and recipient will be the contact selected from the users contact list.
Currently the database is only receiving a user_id to the recipient_id column which is wrong and should be to sender_id column. Sender_id receives nothing.
After reading, some say not to amend the params as this is bad practice. So set a hidden field in the message view (like the body and title) yet this isn't pushing in to the database.
Two questions, is this process an appropriate rails practice? (ask this as new to rails) If not: can you advise another path or direction? If so: any ideas/thoughts why this isn't saving in to the database?
user model
class User < ActiveRecord::Base
has_many :messages, class_name: "Message", foreign_key: "recipient_id"
has_many :sent_messages, class_name: "Message", foreign_key: "sender_id"
has_many :contacts, dependent: :destroy
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_presence_of :firstname, allow_blank: false
validates_presence_of :surname, allow_blank: false
end
message model
class Message < ActiveRecord::Base
belongs_to :sender, class_name: "User", foreign_key: "sender_id"
belongs_to :recipient, class_name: "User", foreign_key: "recipient_id"
validates_presence_of :body, :title
end
Messages controller
class MessagesController < ApplicationController
before_action :message, only: [:show]
before_action :authenticate_user!
def index
#messages = current_user.messages
end
def new
#message = Message.new
end
def create
current_user.messages.create(message_params)
redirect_to '/messages'
end
def show
end
private
def message_params
params.require(:message).permit(:title, :body, :sender_id, :recipient_id)
end
def message
#message = Message.find(params[:id])
end
end
message/new view
<%= form_for #message do |f| %>
<%= hidden_field_tag :sender_id, current_user.id %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
schema
ActiveRecord::Schema.define(version: 20160517131719) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "contacts", force: :cascade do |t|
t.string "firstname"
t.string "surname"
t.string "email"
t.integer "phone"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.integer "user_id"
end
add_index "contacts", ["user_id"], name: "index_contacts_on_user_id", using: :btree
create_table "messages", force: :cascade do |t|
t.string "title"
t.text "body"
t.integer "sender_id"
t.integer "recipient_id"
t.datetime "created_at"
t.datetime "updated_at"
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.string "firstname"
t.string "surname"
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_foreign_key "contacts", "users"
end
Try changing your form to this:
<%= form_for #message do |f| %>
<%= f.hidden_field :sender_id, value: current_user.id %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
Currently the database is only receiving a user_id to the recipient_id
column which is wrong and should be to sender_id column.
In your create action, you have current_user.messages.create(message_params). This creates a message record in the DB with the foreign key's(i.e, recipient_id in your case) value with the parent's(user) id. This is the reason, the recipient_id gets the value of user's id.
Sender_id receives nothing.
This is because the hidden_field set for sender_id is not wrapped with the form builder instance. You need to change
<%= hidden_field_tag :sender_id, current_user.id %>
to
<%= f.hidden_field :sender_id, current_user.id %>
Amended the code base in 'contacts controller' from #contacts = Contact.all to #contacts = current_user.contact so a user can see only their contacts (currently any user sees all the contacts) This is throwing the below error. Tried tweaking but still no success and have checked the database in psql and both have id column. Any ideas or amendment needed in the code?
Failure/Error: <% if #contacts.any? %> ActionView::Template::Error: PG::UndefinedColumn: ERROR: column contacts.user_id does not exist LINE 1: SELECT 1 AS one FROM "contacts" WHERE "contacts"."user_id" ... ^ : SELECT 1 AS one FROM "contacts" WHERE "contacts"."user_id" = $1 LIMIT 1
Contacts Controller
class ContactsController < ApplicationController
before_action :contact, only: [:show, :edit, :update, :destroy] before_action :authenticate_user!
def index
#contacts = current_user.contact end
def new
#contact = Contact.new end
def create
Contact.create(contact_params)
redirect_to '/contacts' end
def show end
def edit end
def update
#contact.update(contact_params)
redirect_to '/contacts/' + "#{#contact[:id]}" end
def destroy
#contact.destroy
redirect_to '/contacts' end
private
def contact_params
params.require(:contact).permit(:firstname, :surname, :email, :phone, :image) end
def contact
#contact = Contact.find(params[:id]) end
end
User controller
class UsersController < ApplicationController
end
Contact model
class Contact < ActiveRecord::Base
belongs_to :user
has_attached_file :image, styles: {thumb: "100x100>"}
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end
User model
class User < ActiveRecord::Base
has_many :contacts, dependent: :destroy
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Index html
<%if user_signed_in? %>
<%= link_to 'Log out', destroy_user_session_path, method: :delete %>
<%end%>
<% if #contacts.any? %>
<% #contacts.each do |contact| %>
<%= link_to image_tag(contact.image.url(:thumb)), contact_path(contact) %>
<h3><%= contact.firstname%> <%=contact.surname%></h3>
<%=contact.email%><br />
<%=contact.phone%>
<br />
<br />
<%end%>
<%else%>
No contacts yet!
<%end%>
<br />
<br />
<%= link_to 'Add a contact', new_contact_path%>
Schema
ActiveRecord::Schema.define(version: 20160504125849) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "contacts", force: :cascade do |t|
t.string "firstname"
t.string "surname"
t.string "email"
t.integer "phone"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
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
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
end
Basically you do not have the user_id in the contacts table. That is the foreign key which is used to define a relation to the users. Add the column and then when you create the contact, add the user's id to the user_id column in the contacts table. Then that should work.
I am unable to insert data in user_preferences table where as I am getting all the attributes in params. I tried inserting value from console by following way since association between User has_one user_preference and UserPreference belongs_to User:
user = User.find(1)
user.user_preferences.title = "MyTitle"
I am getting undefined method "title"
user_preference.rb
class UserPreference < ActiveRecord::Base
belongs_to :user
def self.bgcolor_options
[["Orange", "#FF3300"], ["Green", "#00FF00"], ["Blue", "#0000FF"], ["Pink", "#FF0066"], ["Yellow", "#FFFF00"], ["White", "#FFFFFF"]]
end
def self.font_options
[["Times New Roman", "Times New Roman"], ["Verdana", "Verdana"],["Arial", "Arial"],["sans-serif", "sans-serif"]]
end
end
user_preferences_controller.rb
class UserPreferencesController < ApplicationController
def new
#user_preference = UserPreference.new
end
def create
#user_preference = UserPreference.new(user_pref_params)
#user_preference.save unless user_signed_in?
render 'user_preferences/new'
end
def edit
end
def update
end
private
def user_pref_params
params.require(:user_preference).permit(:title, :bgcolor, :font, :description)
end
end
routes.rb
Rails.application.routes.draw do
resources :user_preferences
post "/user_preferences/new"
devise_for :users
devise_scope :user do
authenticated :user do
root :to => 'user_preferences#new', as: :authenticated_root
end
unauthenticated :user do
root :to => 'devise/registrations#new', as: :unauthenticated_root
end
end
user_preferences/new.html.erb
<%= form_for #user_preference, :url => { :action => "create" } do |u|%>
<div style="background-color:#{current_user.user_preference.bgcolor.nil? ? '#FFFFFF' : current_user.user_preference.bgcolor}">
<p>
<%= u.label :title %><br>
<%= u.text_field :title %>
</p>
<p>
<%= u.label :description %><br>
<%= u.text_field :description %>
</p>
<p> <%= u.label :back_ground_color %><br>
<%= u.select :bgcolor, options_for_select(UserPreference.bgcolor_options) %>
</p>
<p>
<%= u.label :font %><br>
<%= u.select :font, options_for_select(UserPreference.font_options) %>
</p>
<br >
<p>
<%= u.submit %>
</p>
<hr >
<div style="background: #{current_user.user_preferences.bgcolor};"></div>
<div style="background-color:#{current_user.user_preferences.font.nil? ? 'Arial' : current_user.font}">
This is the changes made in background
</div>
</div>
<% end %>
schema.rb
ActiveRecord::Schema.define(version: 20150422034042) do
create_table "user_preferences", force: :cascade do |t|
t.text "title"
t.string "font"
t.text "description"
t.string "bgcolor"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "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.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
end
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
Adding User.rb code
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
has_one :user_preference
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
You're accessing the wrong association on user:
user.user_preferences.title = "MyTitle"
user_preferences is a has_many association, and returns multiple objects. The error itself also mentions this (something like ActiveRecord_Associations_CollectionProxy).
Simply access the has_one association and it will work:
user.user_preference.title = "MyTitle"
for the console part its not a javascript if you want to set to relation you have to use a variabel to assign, and not to use user_preference(s) note the s and its has_one relation and it should be user_preference and in your User Model it should be
# User Model
has_one :user_preference
# Console
user = User.first
preferences = user.user_preference
preferences.title = "MyTitle"
preferences.save
user.reload.preferences.title # should be "MyTitle"