Rails Issues with association between User and Contact - ruby-on-rails

Initially started with Contacts, as expected created a list of populated contacts which correctly allow CRUD. Then set up the login with devise which created Users. When logging in as two different users each should only see their own contacts however currently users sees all the same contacts.
Any help resolving this issue would be appreciated?
(Not sure if should have started with User and then created Contact, feels like this is created backwards.)
Understanding for associations is User 'has_many :contacts' and Contacts 'belongs_to :users' have been changing and spiking to no avail.
ContactsController
class ContactsController < ApplicationController
before_action :contact, only: [ :show, :edit, :update, :destroy] before_action :authenticate_user!
def index
#contacts = Contact.all 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
UsersController
class UsersController < ApplicationController
end
model Contact
class Contact < ActiveRecord::Base
belongs_to :users
has_attached_file :image, styles: {thumb: "100x100>"}
validates_attachment_content_type :image, content_type:
/\Aimage\/.*\Z/
end
model user
class User < ActiveRecord::Base has_many :contacts, dependent: :destroy devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable end
indexhtml
<%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%>
show html
<p><%= image_tag #contact.image.url(:thumb) %></p> <p><%= #contact.firstname %> <%= #contact.surname %></p> <p><%= #contact.phone %></p> <p><%= #contact.email %></p>
<%= link_to 'Edit', edit_contact_path(#contact) %> <%= link_to 'Remove', contact_path(#contact), method: :delete %><br /><br /> <%= link_to 'Contacts', contacts_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

When logging in as two different users each should only see their own
contacts however currently users sees all the same contacts
The problem is with this line #contacts = Contact.all. It holds all the contacts. As you want to display only the current_user's contacts, you just need it to below
#contacts = current_user.contacts
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
It seems the contacts table doesn't have user_id column. Create a new migration to add the same and do rake db:migrate

Related

How can I save the datas checked with simple_form checkbox?

I am beginner with Ruby on Rails, and I am trying to build a little app that permit people to order a pastrie from a cooker, for a day chosen.
When they select the pastrie using a checkbox, I would like that the selected pastrie was saved as pastrie_id in the table fight but instead, I have an issue :
Validation failed: Pastrie must exist.
UPDATE this is working :
<%= f.association :pastrie, as: :check_boxes, label: 'Pastrie' %>
I still have an issue, the saving params are not good I have :
"fight"=>{"pastrie_id"=>["", "1"]},
I tried a lot of solutions found on stackoverflow but nothing seems to work.
I am using Rails 5.2.3
So, this is my schema :
ActiveRecord::Schema.define(version: 2019_06_06_094318) do
create_table "cookers", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "pastrie"
end
create_table "events", force: :cascade do |t|
t.datetime "date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "fights", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "pastrie_id"
t.integer "event_id"
t.integer "cooker_id"
t.index ["cooker_id"], name: "index_fights_on_cooker_id"
t.index ["event_id"], name: "index_fights_on_event_id"
t.index ["pastrie_id"], name: "index_fights_on_pastrie_id"
end
create_table "pastries", force: :cascade do |t|
t.string "pastrie_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
Here is my models :
class Event < ApplicationRecord
has_many :pastries, through: :fights
has_many :cookers, through: :fights
has_many :fights
end
class Fight < ApplicationRecord
belongs_to :pastrie
belongs_to :event
belongs_to :cooker, optional: true
end
class Pastrie < ApplicationRecord
has_many :fights
has_many :events, through: :fights
end
This is my controller. What I understand is : in order to create a Fight, I need an event_id and a pastrie_id (cooker_id is optional). So first, I create a new event (and so I have an event_id), and next, I need to connect a pastrie_id (existing in my seed) to my fight. But this is not working if I am doing that :
class FightsController < ApplicationController
def new
#fight = Fight.new
#event = Event.find(params[:event_id])
#pastries = Pastrie.all
end
def create
#fight = Fight.new(fight_params)
#event = Event.find(params[:event_id])
#fight.event = Event.find(params[:event_id])
#fight.pastrie_id = params[:fight][:pastrie_id]
#fight.save!
redirect_to root_path
end
def show
#events = Event.all
end
def index
#fights = Fight.all
fights_by_event = []
end
private
def fight_params
params.require(:fight).permit(:event_id, :pastrie_id, :cooker_id)
end
end
And my view when I am creating my "fight" :
<div class=margin-bottom>
<h2 class=text-center> Bonjour Linguini, quelles patisseries veux-tu choisir ?</h2>
</div>
<div class="container margin-bottom">
<%= simple_form_for [#event, #fight] do |f| %>
<% #pastries.each do |pastrie| %>
<%= f.label :pastrie_id do %>
<%= f.check_box :pastrie_id, as: :boolean, checked_value: true, unchecked_value: false %> <span><%= pastrie.pastrie_name%></span>
<% end %></br>
<% end %>
<%= f.submit "Valider", class: "btn btn-primary" %>
<% end %>
</div>
And this is my routes if you need this :
Rails.application.routes.draw do
root to: 'pages#home'
resources :events do
resources :fights, only: [:new, :show, :create]
end
resources :fights, only: [:index]
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
In your form change
<%= f.check_box :pastrie_id, as: :boolean, checked_value: true, unchecked_value: false %> <span><%= pastrie.pastrie_name%></span>
To
<%= f.check_box :pastrie_id, as: :boolean, checked_value: pastrie.id, unchecked_value: nil %> <span><%= pastrie.pastrie_name%></span>
In the first version you submit a param of {pastrie_id: true}, which obviously doesn't relate to a Pastry. The second version should submit the ID of the checked box (although if it belongs to only 1 pastry it might make more sense to make these radio buttons)

Creating a nested object with child in a form

I'm a rails noob that's tryin to do something in his app.
My problem is:
I have a Corso model, a Libro model and an Annuncio model. Corso has_many Libro, Libro has_many Annuncio, Annuncio belongs_to Libro and Libro belongs_to Corso. I want a form where the user can create a Libro (that MUST be associated to a Corso) and meanwhile an Annuncio of that Libro must be created. I'm literally freaking out, I saw hundreds of discussions but nothing solved my problem. Every time I change something I get some different errors.
My focus is:
- how to pass the corso_id (I mean, the objects Corso are already defined in the db) to the new Libro when I submit the form;
-I don't see why a Libro object is created (all fields nil) but an Annuncio object doesn't. It seems like the code #libro.annuncios.build in LibroController/new is useless.
I hope you will help me to get this form working.
LibroController:
class LibroController < ApplicationController
def new
#corso = Corso.find(params[:corso_id])
#libro = #corso.libros.build
#libro.annuncios.build
end
def create
#corso = Corso.find(params[:corso_id])
#libro = #corso.libros.build(libro_params)
if #libro.save
redirect_to #libro
else
redirect_to root_path
end
end
def show
#libro = Libro.find(params[:id])
end
def index
end
private
def libro_params
params.require(:libro).permit(:titolo, :autori, :casa_editrice, :edizione, :anno_pubblicazione, :ISBN, :immagine, :corso_id, annuncios_attributes[:prezzo, :note])
end
end
AnnuncioController:
class AnnuncioController < ApplicationController
def new
#annuncio = Annuncio.new
end
def create
#libro = Libro.find(params[:libro_id])
#annuncio = #libro.annuncio.build(annuncio_params)
if #annuncio.save
redirect_to #libro
else
redirect_to root_path
end
end
private
def annuncio_params
params.require(:annuncio).permit(:prezzo, :note)
end
end
Libro Model:
class Libro < ApplicationRecord
belongs_to :corso, inverse_of: :libros
has_many :annuncios, inverse_of: :libro
accepts_nested_attributes_for :annuncios
end
Annuncio Model:
class Annuncio < ApplicationRecord
belongs_to :utente, inverse_of: :annuncios
belongs_to :libro, optional: true, inverse_of: :annuncios
end
Corso Model:
class Corso < ApplicationRecord
belongs_to :facolta
has_many :libros
validates :nome, uniqueness: true
end
routes.rb (a little messed up)
Rails.application.routes.draw do
get 'facolta/new'
get 'sessions/create'
get 'sessions/destroy'
get 'users/new'
get 'corso/index'
get 'auth/:provider/callback', to: 'sessions#create'
get 'auth/failure', to: redirect('/')
get 'signout', to: 'sessions#destroy', as: 'signout'
resources :sessions, only: [:create, :destroy]
resource :home, only: [:show]
root 'facolta#index'
get 'corso_new' => 'corso#new'
get 'libro_new' => 'libro#new'
get 'about_us' => 'static_pages#about_us'
get 'faq' => 'static_pages#faq'
resources :facolta do
resources :corso
end
resources :corsos, shallow: true do
resources :libro
end
resources :libros do
resources :annuncio
end
resources :user do
resources :annuncio
end
end
views/libro/new
<h1>FORM DI REGISTRAZIONE HERE</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for([#corso, #libro]) do |libro| %>
<p>
<%= libro.label :titolo %>
<%= libro.text_field :titolo %>
</p>
<p>
<%= libro.label :autori %>
<%= libro.text_field :autori %>
</p>
<p>
<%= libro.label :casa_editrice %>
<%= libro.text_field :casa_editrice %>
</p>
<p>
<%= libro.label :edizione %>
<%= libro.text_field :edizione %>
</p>
<p>
<%= libro.label :anno_pubblicazione %>
<%= libro.text_field :anno_pubblicazione %>
</p>
<p>
<%= libro.label :ISBN %>
<%= libro.text_field :ISBN %>
</p>
<p>
<%= libro.label :immagine %>
<%= libro.text_field :immagine %>
</p>
<%= libro.fields_for :annuncios do |annuncio| %>
<p>
<%= annuncio.label :prezzo %>
<%= annuncio.text_field :prezzo %>
</p>
<p>
<%= annuncio.label :note %>
<%= annuncio.text_field :note %>
</p>
<% end %>
<%= libro.hidden_field :corso_id, value: params[:post_id]%>
<%= libro.submit "Inserisci il libro", class: "btn btn-primary" %>
<% end %>
</div>
</div>
schema.rb
create_table "annuncios", force: :cascade do |t|
t.integer "user_id"
t.integer "libro_id"
t.string "prezzo"
t.text "note"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["libro_id"], name: "index_annuncios_on_libro_id"
t.index ["user_id"], name: "index_annuncios_on_user_id"
end
create_table "corsos", force: :cascade do |t|
t.string "nome"
t.integer "facolta_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["facolta_id"], name: "index_corsos_on_facolta_id"
end
create_table "facolta", force: :cascade do |t|
t.string "nome"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "libros", force: :cascade do |t|
t.string "titolo"
t.string "autori"
t.string "casa_editrice"
t.string "edizione"
t.string "anno_pubblicazione"
t.string "ISBN"
t.string "immagine"
t.integer "corso_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["corso_id"], name: "index_libros_on_corso_id"
end
create_table "users", force: :cascade do |t|
t.string "provider"
t.string "uid"
t.string "name"
t.string "oauth_token"
t.datetime "oauth_expires_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email"
end
EDIT: edited with #arieljuod advices
You don't need to merge the corso_id here: #libro = #corso.libros.build(libro_params.merge({corso_id: #corso.id})). ActiveRecord already sets the corso_id since you are doing #corso.libros.build(...).
You also don't need that hidden_field with the Corso id since you already have that from the URL.
You may want to do #libro = #corso.libros.build on your new action too.
And finally, I think this is the main problem: this is wrong belongs_to :corso, inverse_of: :corsos, it should be inverse_of: :libros
Fix the other things I point out too to clean up your code.
EDIT:
to add a select do something like this:
= libro.select :corso_id, options_from_collection_for_select(Corso.all, :id, :name)

How can I set my controller and views when I have two Many-to-Many association?

My aim is to organize uploaded posts by categories. These categories are shown on the nav bar and if you click one of the category's names, you will see the posts assigned with the category. When uploading a post, you can assign it with multiple categories too. So, I think this is like many posts can have many categories and many categories can have many posts.
This is how I want my posts organized by categories
However, I cannot set things right in my posts_controller.rb, posts/index.html.erb, posts/show.html.erb, and _navigation.html.erb
post.rb
class Post < ActiveRecord::Base
#This validates presence of title, and makes sure that the length is not more than 140 words
validates :title, presence: true, length: {maximum: 140}
#This validates presence of body
validates :body, presence: true
has_many :categorizations
has_many :categories, :through => :categorizations
end
category.rb
class Category < ApplicationRecord
has_many :categorizations
has_many :posts, :through => :categorizations
end
categorization.rb
class Categorization < ApplicationRecord
belongs_to :post
belongs_to :category
end
Then, here are these controller and views I am confused with:
posts_controller.rb
class PostsController < ApplicationController
before_action :find_post, only: [:edit, :update, :show, :delete]
before_action :authenticate_admin!, except: [:index, :show]
# Index action to render all posts
def index
if params.has_key?(:category)
#category = Category.find_by_name(params[:category])
#posts = Post.where(category: #category)
else
#posts = Post.all
end
end
# New action for creating post
def new
#post = Post.new
end
# Create action saves the post into database
def create
#post = Post.new(post_params)
if #post.save
flash[:notice] = "Successfully created post!"
redirect_to post_path(#post)
else
flash[:alert] = "Error creating new post!"
render :new
end
end
# Edit action retrives the post and renders the edit page
def edit
end
# Update action updates the post with the new information
def update
#post = Post.find(params[:id])
if #post.update_attributes(post_params)
flash[:notice] = "Successfully updated post!"
redirect_to posts_path(#posts)
else
flash[:alert] = "Error updating post!"
render :edit
end
end
# The show action renders the individual post after retrieving the the id
def show
end
# The destroy action removes the post permanently from the database
def destroy
#post = Post.find(params[:id])
if #post.present?
#post.destroy
flash[:notice] = "Successfully deleted post!"
redirect_to posts_path
else
flash[:alert] = "Error updating post!"
end
end
private
def post_params
params.require(:post).permit(:title, :body, category_ids: [])
end
def find_post
#post = Post.find(params[:id])
end
end
index.html.erb
<div class="container">
<div class="col-sm-10 col-sm-offset-1 col-xs-12">
<% #posts.each do |post| %>
<div class="col-xs-12 text-center">
<div class="text-center">
<h2><%= post.title %></h2>
<h6><%= post.created_at.strftime('%b %d, %Y') %></h6>
</div>
<div>
<%= raw post.body.truncate(358) %>
</div>
<div class="text-center">
<%= link_to "READ MORE", post_path(post) %>
</div>
<% if admin_signed_in? %>
<%= link_to "Show", post_path(post), class: "btn btn-primary" %>
<%= link_to "Edit", edit_post_path(post), class: "btn btn-default" %>
<%= link_to "Delete", post_path(post), class: "btn btn-danger", data: {:confirm => "Are you sure?"}, method: :delete %>
<% end %>
<hr />
</div>
<% end %>
</div>
</div>
show.html.erb
<div class="col-sm-11 col-xs-12 blog-content">
<h2 class="text-center"><%= #post.title %></h2>
<h1 class="text-center"><%= #category.name %></h1>
<h5 class="text-center"><%= #post.created_at.strftime('%b %d, %Y') %></h5>
<div class="text-center"><%= raw #post.body %></div>
</div>
_navigation.html.erb(part of it)
<ul class="nav navbar-nav navbar-left">
<% Category.all.each do |cat| %>
<li class="text-center"><%= link_to cat.name, posts_path(category: cat.name) %></li>
<% end %>
</ul>
Just in case, schema.rb
ActiveRecord::Schema.define(version: 2018_11_07_082317) do
create_table "admins", 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 "avatar"
t.index ["email"], name: "index_admins_on_email", unique: true
t.index ["reset_password_token"], name: "index_admins_on_reset_password_token", unique: true
end
create_table "categories", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "categories_posts", id: false, force: :cascade do |t|
t.integer "category_id"
t.integer "post_id"
end
create_table "categorizations", force: :cascade do |t|
t.integer "post_id"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "ckeditor_assets", force: :cascade do |t|
t.string "data_file_name", null: false
t.string "data_content_type"
t.integer "data_file_size"
t.string "type", limit: 30
t.integer "width"
t.integer "height"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["type"], name: "index_ckeditor_assets_on_type"
end
create_table "posts", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
In show view you have
<h1 class="text-center"><%= #category.name %></h1>
But you don't define #category in show action. If you want to list categories, it should be
<h1 class="text-center"><%= #post.categories.pluck(:name).join(', ') %></h1>
Btw, looks like you have useless table categories_posts in the schema.rb
Update:
About index action - you should change query for #posts, since the post doesn't have a category column, but he has categories association:
def index
if params.has_key?(:category)
# you can remove #category defining if you don't need it somewhere in view
#category = Category.find_by_name(params[:category])
#posts = Post.joins(:categories).where(categories: { name: params[:category] } )
else
#posts = Post.all
end
end
Note, it is better to use id for the query, not name, searching by id is faster. You need to change link in navbar to link_to cat.name, posts_path(category: cat.id) for it and replace name with id in the query. And it is better to move the whole query to named scope in the Post model.

Rails association user & contacts throwing error

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.

Unable to insert data in table using form to submit data

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"

Resources