validates_associated not being triggered when I expect - ruby-on-rails-3

I have two tables, user and skill, that are connected by a join table called user_skill. Each UserSkill has a current_proficiency_level and an interest_level.
Everything worked perfectly fine until I put a validates_numericality_of :current_proficiency_level on UserSkill. Now I get the following error when I try to save my User edit form. I only get the error when I have at least one non-numeric current_proficiency_level. When everything is valid, it saves fine.
Failed to replace user_skills because one or more of the new records could not be saved.
This tells me that the UserSkill records probably aren't getting validated when I try to save my User. Here's my User class (with some irrelevant code omitted for clarity):
class User < ActiveRecord::Base
has_many :posts
has_many :user_skills
has_many :skills, :through => :user_skills
validates_associated :user_skills
def attach_skills(current_proficiency_levels, interest_levels)
self.user_skills.destroy_all
self.user_skills = Skill.all.map { |skill|
user_skill = UserSkill.find_or_create_by_user_id_and_skill_id(self.id, skill.id)
user_skill.assign_attributes(
:current_proficiency_level => current_proficiency_levels[skill.id.to_s].negative_if_blank,
:interest_level => interest_levels[skill.id.to_s].negative_if_blank
)
user_skill
}
end
end
And here is my UserSkill class. I haven't omitted anything here; it's just that short.
class UserSkill < ActiveRecord::Base
belongs_to :user
belongs_to :skill
validates_numericality_of :current_proficiency_level
validates_numericality_of :interest_level
end
Why isn't validates_numericality_of being run when I save my User?

Related

Rails - belongs_to ignores inverse_of

I've got two AR Models:
class User < ActiveRecord::Base
set_primary_key 'email'
attr_readonly :email, :etag, :full_name, :google_id, :photo_url, :suspended
has_one :sip_user, inverse_of: :user, foreign_key: 'user_email'
end
class SipUser < ActiveRecord::Base
set_primary_key 'user_email'
attr_readonly :user_email, :sip_id, :sip_password,
:int_number, :ext_number, :mobile_number
belongs_to :user, inverse_of: :sip_user, foreign_key: 'email'
end
Querying from User to SipUser works perfectly:
User.find('email#company.com').sip_user
returns the correct matching SIP user.
SipUser.find('email#company.com')
also returns a correct DB entry, but
SipUser.find('email#company.com').user
doesn't. But it should, according to the belongs_to :user, inverse_of: :sip_user.
Any ideas?
The inverse_of has no nothing to do with the SipUser.find('email#company.com').user expression. You specification in SipUser means this: For this sip_user, find the user that has user.email= sip_user.email. This leads to this query SELECT * FROM USERS WHERE email='email#company.com' LIMIT 1;
Your inverse_of would help with this case sip_user.user.sip_user. If you do not have inverse_of, it will use two query, first one finds the user for the sip_user, and a second one finds the sip_user for the sip_user.user. With inverse_of, it will only send the first query and immediately returns sip_user as sip_user.user.sip_user. So it helps with your DB efficiency.

Rails Association (belongs_to) dilemma

I have a User model:
class User < ActiveRecord::Base
has_many :cards
end
and a Card model:
class Card< ActiveRecord::Base
belongs_to :user, :foreign_key => "owner_id"
end
the card model also has an attribute called "owner_id", which I'd like to use in way like this:
Card.first.owner which will retrieve the User which owns that card
my problem as that, I know that rails will automagically connect the id's in the association but that doesnt happen.
in the CardController, rails get stuck in the create action on the line
#card=current_user.cards.new(params[:card])
and says unknown attribute: user_id
I've done db:migrate and it still won't work.
must I do as follows for it to work?
#card = Card.new(params[:card])
#card.owner_id=current_user.id
or am I missing something?
First of all, you don't need a owner_id column for this. All you need is
class User
has_many :cards
end
This will give you #user.cards
class Card
belongs_to :owner, :class_name => "User", :foreign_key => "user_id"
end
This will give you #card.owner

rails 3.1 model and view and controller association with 3 tables association

class Hashtag < ActiveRecord::Base
has_many :messages
end
class User < ActiveRecord::Base
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :hashtag, :foreign_key => "hashtag_id"
belongs_to :user, :foreign_key => "user_id"
end
Now if in the hashtag's show view we want to show all the messages belonging to hashtag and also an input box to create a new message.
Any kind of code examples or links or videos will be helpful ?
If the association is set up correctly, calling hashtag.messages will return an array of messages associated with that specific hashtag.
To create messages on the hashtag 'show' page you'll need to create the new message in hashtag#show.
#hashtag.messages.build
On the hashtags/show.html page, add a form for the user to edit the message. Then submit the message to message#create.

Rails calling User record from Friends model

I've built a simple Friend model, which allows Users to have multiple friends. Here's what that looks like:
class Friend < ActiveRecord::Base
belongs_to :user
class User < ActiveRecord::Base
has_many :friends
Each friend record just has an id, user_id and friend_id. The user_id is the id of the user it belongs to and the friend_id is the id of user they are befriending.
Here's my problem
I'm not quite sure how to display a list of a particular user's friends. #user.friends will give me a list of all the friend records they have, but not the user accounts of those friends.
For instance, I am trying to build a show page for the friends controller:
class FriendsController < ApplicationController
def show
#user = current_user
end
SHOW.HTML.ERB
<% if #user.friends.count > 0 %>
<% #user.friends.each do |friend| %>
<div class="entry">
<%= friend.username %>
This does not work because friend in this case does not have username. I need to do something like this in my controller:
#friend = User.find_by_id(friend.friend_id)
But I'm not sure how I would call that in my view in the #user.friends loop. Any thoughts appreciated. Let me know if I need to be more clear.
UPDATE
I've updated my User model like so:
has_many :friends, :include => :user
has_many :friended_users, :through => :friends, :source => :user, :uniq => true
However, when I run #user.friended_users it's giving me the user_ids (which is the same as #user) rather than friend_ids.
How can I tweak that relationship so it's linking to the friend_id rather than user_id?
The more I think about it, I think I may not have set up the relationship properly in the first place. Maybe a User should has_many :users, through => 'friends', but that doesn't really make sense...
UPDATE
I've updated my models based on #twooface's input:
class User < ActiveRecord::Base
has_many :friendships
has_many :friends, :through => :friendships
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => 'User'
class Friend < ActiveRecord::Base
has_many :friendships
has_many :users
I'm just not sure what my Friends table should look like. I assume it should have a primary key and a user_id? If I create a friendship and friend record, I can do friendship.user and friendship.friend and get the correct results, but user.friends gives me an empty hash...
I think your relations are built a bit wrong. Try something like this:
class User < ActiveRecord::Base
has_many :friends
has_many :friendships
has_many :friends, :through => :friendships
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => 'User'
# This class has :user_id and :friend_id
Then everything will be simpler. Every user will have an array of friends that will be just users.
User.first.friends
Will return an array of Users that this User friends.
Hope this helps.

How do i create an object if it has more than one belongs_to?

I have the following:
class Org < ActiveRecord::Base
has_many :users
has_many :entries
end
class Entry < ActiveRecord::Base
belongs_to :org
belongs_to :user
validates_presence_of :entry_text
end
class User < ActiveRecord::Base
belongs_to :org
has_many :entries
validates_uniqueness_of :user_name
validates_presence_of :user_name, :length => { :minimum => 3 }
end
I can Create Orgs and Users... How do i create an entry if there are two belongs_to? and what is this pattern called?
Double nested resources are tricky. The trick with users usually is to keep it out of your desired entry path.
Your question is kind of broad, but if you specify more information, people would be able to help you better. Also, I would recommend using the gem Devise for your user management system. Since you're using 'users' I would assume you want users from orgs to create entries. The entry created would be a part of org and the user would be the session's current user. Sorry if I am wrong to assume this.
Your routes.rb file can look something like this (assuming rails 3):
resources :orgs do
resources :entries
end
Then the create of your entry controller would look like:
#entry = #org.entries.new(params[:topic])
#entry.user = current_user #or however you are managing the current user's session.
And you'd want to set the org for the entire class by making a method that loads your current org and do a before_filter :loadOrg
def loadOrg
#org = Org.find(params[:id])
end
This is of course assuming your path is something like: /org/(id)/entry/(entry_id)
and not
/org/(id)/user/(user_id)/entry/(entry_id)
which in my opinion is unnecessary and can lead to more problems. You can always create a userpage model that calls all entries by users, but the default route doesn't necessarily have to include users in the path.
I don't see any problem.
#entry = Entry.create(:entry_text => "Hello World!")
Now questions to clarify what do you need:
Can #entry belongs both org and user at the same time? Or it can belongs to only one of them?
Should #entry belongs to at least one of them?
If #entry supposed to belong only one of them, so you should use Polymorphism
http://railscasts.com/episodes/154-polymorphic-association
class Entry < ActiveRecord::Base
belongs_to :textable, :polymorphic => true
validates_presence_of :entry_text
end
class Org < ActiveRecord::Base
has_many :users
has_many :entries, :as => :textable
end
class User < ActiveRecord::Base
belongs_to :org
has_many :entries, :as => :textable
validates_uniqueness_of :user_name
validates_presence_of :user_name, :length => { :minimum => 3 }
end