I'm fairly new to rails and trying to add a belongs_to association to my Devise User model.
The error I get when trying to render the view:
NoMethodError in Devise/registrations#edit
undefined method `department_id' for #
This error is occurring on the collection_select in my view. Isn't this method provided by the belongs_to association?
User model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
belongs_to :department
end
Edit view
%h2
Edit #{resource_name.to_s.humanize}
= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f|
= devise_error_messages!
%p
= f.label :email
%br/
= f.text_field :email
%p
= f.label :department
%br/
= collection_select(resource_name, :department_id, Department.all, :id, :name)
%p
...
As mentioned by #njorden, be sure to do the following:
migrate to add department_id to your users table
attr_accessible :department_id to allow mass assignment via edit registration form
This really should work, I have a belongs_to :business on my devise User model and an analogous collection_for_select works great. The only thing I can think of is that maybe your migrations haven't run and you don't have the user.department_id column yet?
That looks backwards. collection_select would be appropriate for the has_many side of the association. Note that the semantic hint here is that when an object belongs_to another object it's singular. There is no collection involved. You ask for department and get back a one object. From the other direction, if your Department was set to has_many :users then asking for users would give you a list of users.
Take a look at the docs for select. They give a simple example of what you're trying to do with departments (in the form of choosing an author for a blog post).
Just to add my case, I had a similar issue. Initially each user had a department with a department_id, then I moved to a has_many, and forgot to remove the department_id from user. Solution was to delete department_id off of user.
Related
My rails app has a User model and a Role model. Each User belongs to one role and each role has many users. There three methods defined in the user model to check the role of that user def admin?, def user?, and def expert?.
The User class:
class User < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
validates_presence_of :name
validates_presence_of :avatar
validates_integrity_of :avatar
validates_processing_of :avatar
before_save :assign_role
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :role
has_many :items
belongs_to :organization
has_many :expertkeywordmodels
has_many :keywords, through: :expertkeywordmodels
def assign_role
self.role = Role.find_by name: "Admin" if self.role.nil?
end
def self.with_role(role)
my_role = Role.find_by_name(role)
where(:role => my_role)
end
def admin?
self.role.name == "Admin"
end
def user?
self.role.name == "User"
end
def expert?
self.role.name == "Expert"
end
end
The Role class:
class Role < ActiveRecord::Base
has_many :users
end
I am trying to create a collection_select only with users that have expert role. Something like:
<%= collection_select(:keyword, :user_ids, User.where('expert?'), :id, :name, {prompt: true}, {:multiple => true}) %>
But it does not recognize expert? as a method. I was wondering if anyone knows how can I perform this query.
I am sorry if this is a naive question as I am new to rails.
Thanks,
Amir
User.where('expert?') doesn't really makes sense for the database, because it would translate to SQL like:
SELECT * FROM users WHERE expert?;
And obviously expert? isn't a valid SQL expression. expert? is only available in the context of your code.
Instead you need to write that logic in a way that translates to valid SQL and makes sense in the context of your database schema. My guess is that the following might work:
User.joins(:role).where(roles: { name: 'Expert'})
You might want to define a scope in your User model, like this:
scope :experts, -> { joins(:role).where(roles: { name: 'Expert'}) }
Than User.experts would return all users that have the expert role.
Not for nothing, but you have three methods in your user model that all set the same field, just differently.
def role(role_type)
self.role.name = role_type
end
To get your desired require to work properly - you can either write a scope or a method.
def get_roles(role_type)
User.role.name = role_type
end
Rail Guides are always extremely helpful. http://guides.rubyonrails.org/active_record_querying.html#passing-in-arguments
i'm building a social media website with Ruby on Rails and i'm following instructions from teamtreehouse.com . Every time i make a new status or go to the index page i get this message
undefined method `full_name' for nil:NilClass
<p>
<strong>Name:</strong>
<%= #status.user.full_name %>
</p>
I coded my pages to show the full name with this
<%= #status.user.full_name %>
and
<%= status.user.full_name %>
for the index page.
I have included all of these snippets of code into my project as well
status.rb
class Status < ActiveRecord::Base
attr_accessible :content, :user_id
belongs_to :user
end
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me,
:first_name, :last_name, :profile_name
# attr_accessible :title, :body
def full_name
first_name + " " + last_name
end
end
I've tried using rake db:reset and rake db:migrate but nothing seems to solve the error problem. Thank you for your help!
As per the error,
undefined method `full_name' for nil:NilClass
which means that
#status.user = nil
i.e., the particular status instance that you are looking at(#status) doesn't have an associated user record.
You can verify it by going to rails console
Status.find(pass_the_id) ## pass the id of #status instance
You will notice that user_id is nil for that record.
Set the value to an existing user_id and try again.
Note: you might need to take a deeper look at how you are storing a status in your application. I suppose you are missing to store user_id attribute there
Looks like you'd need to include has_many :statuses in the User model
You may also wish to use the .delegate() method:
class Status < ActiveRecord::Base
attr_accessible :content, :user_id
belongs_to :user
delegate :full_name, to :user, prefix: :author
end
This should allow you to call #status.author_full_name
I have a polymorphic relationship for my User model. I am using Devise.
When I try to edit the user's details, I get the following error:
undefined method `primary_key' for ActiveSupport::HashWithIndifferentAccess:Class
The data submitted through the form is:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"Ap0JP2bs/w9J6iI9rZahiKR1K8UEIi7rp33a4OutMbo=",
"user"=>{"email"=>"some_email#yahoo.com",
"rolable"=>{"first_name"=>"Christopher",
"last_name"=>"Columbus",
"city"=>"16"}},
"commit"=>"Update"}
The controller method is:
def update
#user = User.find(current_user.id)
if #user.update_attributes(params[:user])
redirect_to edit_user_registration_path, notice: 'Your profile was successfully updated.'
else
redirect_to edit_user_registration_path, error: "Something went wrong, couldn't update your profile!."
end
end
The models:
1. User
class User < ActiveRecord::Base
belongs_to :rolable, :polymorphic => true
# Devise business
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :remote_avatar_url, :avatar, :login, :username, :email, :password, :password_confirmation, :remember_me
# For authenticating with facebook
attr_accessible :provider, :uid, :rolable
devise :omniauthable, :omniauth_providers => [:facebook]
# For authenticating with both username or email
attr_accessor :login
# Upload avatar
mount_uploader :avatar, AvatarUploader
# Makes username necessary
validates :username, :presence => true
end
2. Customer
class Customer < ActiveRecord::Base
has_one :user, :as => :rolable
has_one :preferences, :class_name => "CustomerPreferences"
belongs_to :city
attr_accessible :first_name, :last_name
end
What's the problem?
Based on your request hash, you are passing the rolable attribute as:
"rolable"=>{"first_name"=>"Cristian",
"last_name"=>"Gavrila",
"city"=>"16"}
You can't do this unless you specify that the User model accepts nested attributes for rolable. However, you have setup your User as belonging to a Rolable rather than the other way around. Nested attributes aren't designed to handle this inverse relationship - you may want to reconsider what you are trying to accomplish here, and modify the relationship accordingly.
For instance, you may want to turn your hash inside out and pass the rolable attributes with the user attributes embedded within. Or you may want to turn rolable into a has_one association.
New to Rails and I have read the association manuals and tried to find an answer to why my association is not working.
I chose to separate the Profile from the user for ease of association to different user types and functions - I will have 3-4 different models for each type of user.
I have:
User model using Devise
Profile Model Called Temper
Dashboard View
If I am trying to call the information from the Profile model on the dashboard for the current user the code below "should" work if I am reading the guides right.
ERROR IS:
enter code hereundefined method `temp_phone_n' for #<User:0x007fbb8c62e4c8>
I see that it IS picking up the current user and trying to associate it but to no avail.
Can anyone tell me where I am going wrong.
Below:
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me,
:first_name, :last_name, :profile_name, :user_id
# attr_accessible :title, :body
has_one :temper
def full_name
first_name + " " + last_name
end
end
Temper.rb
class Temper < ActiveRecord::Base
attr_accessible :first_name, :last_name, :temp_about, :temp_avail, :temp_city, :temp_country, :temp_email, :temp_phone_d, :temp_phone_n, :temp_pors, :temp_skills, :temp_st_address_1, :temp_st_address_2, :user_id
has_one :user
end
Dashboard/index.html.erb
<div class="span5">
<ul>
<li><h4>Name:</h4> <%= current_user.full_name %></li>
<li><h4>Phone Number:</h4> <%= current_user.temp_phone_n %></li>
<li><h4>Email:</h4> <%= current_user.email %></li>
<li><h4>City:</h4> Toronto</li>
<li><h4>Member Since:</h4> <%= current_user.created_at.strftime("%B %d, %Y") %></li>
</ul>
</div>
Any assistance would be appreciated
You can access it like that:
current_user.temper.temp_phone_n
And your relationship is wrong, you can't write has_one to both side of the relationship
User.rb
has_one :temper
Temper.rb
belongs_to :user
Right now, I have two models: User and Micropost.
The User model is working with Devise.
Example of the files involved:
user_controller.html.erb:
class PagesController < ApplicationController
def index
#user = current_user
#microposts = #user.microposts
end
end
index.html.erb:
<h2>Pages index</h2>
<p>email <%= #user.email %></p>
<p>microposts <%= render #microposts %></p>
microposts/_micropost.html.erb
<p><%= micropost.content %></p>
micropost.rb:
class Micropost < ActiveRecord::Base
attr_accessible :content
belongs_to :user
end
user.rg:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
has_many :microposts
end
Now I want to create comments for the microposts:
Each comment should belong to its respective micropost and user (commenter). Not sure how to do this (is it a good situation to use polymorphic associations?).
An user should have many microposts and comments (not sure how to co this either).
I have no idea how to make it so that the comment is made the the user who is currently signed in (I think I have to do something with Devise's current_user).
Any suggestions to accomplish this? (Sorry, I'm a Rails beginner)
No, nothing you've said suggests that you need polymorphic associations. What you need is a comments model with a schema something like the following:
create_table :comments do |t|
t.text :comment, :null => false
t.references :microposts
t.references :user
t.timestamps
end
And then
# user.rb
has_many :microposts
has_many :comments
# microposts.rb
has_many :comments
You will probably want nested routes for your comments. So, in your routes.rb you'll have something like
#routes.rb
resources :microposts do
resources :comments
end
.. and in your comments controller, yes, you'll assign the value of comment.user something like the following...
# comments_controller.rb
def create
#comment = Comment.new(params[:comment])
#comment.user = current_user
#comment.save ....
end
You might want to look at the Beginning Rails 3 book, which would walk you through this.