i'm breaking my head to get the user of this situation:
a conversation model:
has_many :conversation_participants, :dependent => :destroy
has_many :users,
:through => :conversation_participants
has_many :messages, :dependent => :destroy
has_one :display_message,
:class_name => 'Message',
:order => 'created_at DESC'
def participants(options={})
if options[:not].is_a? User
users - [options[:not]]
else
users
end
end
and conversation_participants:
belongs_to :user
belongs_to :conversation
attr_accessible :user_id
on a conversation helper:
def self_or_other
#conversation.conversation_participants.find_by_user_id(:not => current_user)
end
please, someone could clear me how to get the other user inside conversation_participants model?
I believe like follows:
#conversation.conversation_participants.where.not(user_id: current_user.id).first
Related
I've got users and organisations with a join model UsersOrganisation. Users may be admins of Organisations - if so the is_admin boolean is true.
If I set the is_admin boolean by hand in the database, Organisations.admins works as I'd expect.
In the console, I can do Organisation.first.users << User.first and it creates an organisations_users entry as I'd expect.
However if I do Organisation.first.admins << User.last it creates a normal user, not an admin, ie the is_admin boolean on the join table is not set correctly.
Is there a good way of doing this other than creating entries in the join table directly?
class User < ActiveRecord::Base
has_many :organisations_users
has_many :organisations, :through => :organisations_users
end
class Organisation < ActiveRecord::Base
has_many :organisations_users
has_many :users, :through => :organisations_users
has_many :admins, :through => :organisations_users, :class_name => "User",
:source => :user,
:conditions => {:organisations_users => {:is_admin => true}}
end
class OrganisationsUser < ActiveRecord::Base
belongs_to :organisation
belongs_to :user
end
You can always override the << method of the association:
has_many :admins do
def <<(user)
user.is_admin = true
self << user
end
end
(Code has not been checked)
there are some twists with the has_many :through and the << operator. But you could overload it like in #Erez answer.
My approach to this is using scopes (I renamed OrganisationsUsers to Memberships):
class User < ActiveRecord::Base
has_many :memberships
has_many :organisations, :through => :memberships
end
class Organisation < ActiveRecord::Base
has_many :memberships
has_many :members, :through => :memberships, :class_name => 'User', :source => :user
# response to comment:
def admins
memberships.admin
end
end
class Memberships < ActiveRecord::Base
belongs_to :organisation
belongs_to :user
scope :admin, where(:is_admin => true)
end
Now I create new admins like this:
Organisation.first.memberships.admin.create(:user => User.first)
What I like about the scopes is that you define the "kind of memberships" in the membership class, and the organisation itself doesn't have to care about the kinds of memberships at all.
Update:
Now you can do
Organisation.first.admins.create(:user => User.first)
You can try below code for organization model.
class Organisation < ActiveRecord::Base
has_many :organisations_users
has_many :organisations_admins, :class_name => "OrganisationsUser", :conditions => { :is_admin => true }
has_many :users, :through => :organisations_users
has_many :admins, :through => :organisations_admins, :source => :user
end
I'm working on some app, I have User, Post and Report models so users can report other users, or posts. So I did this:
class Report < ActiveRecord::Base
belongs_to :user
belongs_to :reportable, :polymorphic => true
...
class User < ActiveRecord::Base
has_many :reports, :dependent => :destroy
has_many :reported_users, :through => :reports, :source => :reportable, :source_type => 'User'
has_many :reported_posts, :through => :reports, :source => :reportable, :source_type => 'Post'
has_many :reports, :as => :reportable, :dependent => :destroy
...
class Post < ActiveRecord::Base
has_many :reports, :as => :reportable, :dependent => :destroy
...
And my user spec looks like:
it 'reports another user' do
#reporter = FactoryGirl.create(:user)
#reported = FactoryGirl.create(:user)
Report.create!(:user => #reporter, :reportable => #reported)
Report.count.should == 1
#reporter.reported_users.size.should == 1
end
And I get an error saying:
User reports another user
Failure/Error: #reporter.reported_users.size.should == 1
expected: 1
got: 0 (using ==)
Can't figure out whats wrong, can I use has_many :reports and has_many :reports, :as => :reportable together in a model? Also, how can I get the reporters for a user? Let's say I want to have #user.reporters to get all other users who have reported a particular user.
Changing the second has_many :reports to has_many :inverse_reports solved the problem:
class User < ActiveRecord::Base
has_many :reports, :dependent => :destroy
has_many :reported_users, :through => :reports, :source => :reportable, :source_type => 'User'
has_many :reported_posts, :through => :reports, :source => :reportable, :source_type => 'Post'
has_many :inverse_reports, :class_name => 'Report', :as => :reportable, :dependent => :destroy
Now I guess I can also get the reporters for each user like:
has_many :reporters, :through => :inverse_reports, :source => :user
I have a Post model:
class Post < ActiveRecord::Base
belongs_to :user
has_many :taggings, :dependent => :destroy
has_many :tags, :through => :taggings
attr_writer :tag_names
after_save :assign_tags
before_create :init_sort_column
def tag_names
#tag_names || tags.map(&:name).join(" ")
end
private
def assign_tags
self.tags = []
return if #tag_names.blank?
#tag_names.split(" ").each do |name|
tag = Tag.find_or_create_by_name(name)
self.tags << tag unless tags.include?(tag)
end
end
end
a Tag model:
class Tag < ActiveRecord::Base
has_many :taggings, :dependent => :destroy
has_many :posts, :through => :taggings
has_many :subscriptions
#has_many :subscribed_users, :source => :user, :through => :subscriptions
end
and a User model:
class User < ActiveRecord::Base
(Code related to Devise)
has_many :posts, :dependent => :destroy
has_many :subscriptions
has_many :subscribed_tags, :source => :tag, :through => :subscriptions
has_many :subscribed_posts, :source => :posts, :through => :subscribed_tags
attr_writer :subscribed_tag_names
after_save :assign_subscribed_tags
def subscribed_tag_names
#subscribed_tag_names || subscribed_tags.map(&:name).join(' ')
end
private
def assign_subscribed_tags
#self.subscribed_tags = []
return if #subscribed_tag_names.blank?
#subscribed_tag_names.split(" ").each do |name|
subscribed_tag = Tag.find_or_create_by_name(name)
self.subscribed_tags << subscribed_tag unless subscribed_tags.include?(subscribed_tag)
end
end
end
In the index page users only see posts with tags they have subscribed to:
posts_controller.rb:
#posts = current_user.subscribed_posts.paginate(:page => params[:page],
:per_page => 5,
:order => params[:order_by])
Now say there is a post with the tags food and drinks, and the user has subscribed to these two tags. He will see the post twice; it seems like it is appearing once as a post tagged as food and then as a post tagged as drinks.
Is there a way of preventing posts like this from appearing twice?
Add :uniq => true as a parameter to the has_many in the User model:
has_many :subscribed_posts, :source => :posts, :through => :subscribed_tags, :uniq => true
The docs at http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many-label-Options says:
:uniq
If true, duplicates will be omitted from the collection. Useful
in conjunction with :through.
I have developed an application and I seem to be having some problems with my associations. I have the following:
class User < ActiveRecord::Base
acts_as_authentic
has_many :questions, :dependent => :destroy
has_many :sites , :dependent => :destroy
end
Questions
class Question < ActiveRecord::Base
has_many :sites, :dependent => :destroy
has_many :notes, :through => :sites
belongs_to :user
end
Sites (think of this as answers to questions)
class Site < ActiveRecord::Base
acts_as_voteable :vote_counter => true
belongs_to :question
belongs_to :user
has_many :notes, :dependent => :destroy
has_many :likes, :dependent => :destroy
has_attached_file :photo, :styles => { :small => "250x250>" }
validates_presence_of :name, :description
end
When a Site (answer) is created I am successfully passing the question_id to the Sites table but I can't figure out how to also pass the user_id. Here is my SitesController#create
def create
#question = Question.find(params[:question_id])
#site = #question.sites.create!(params[:site])
respond_to do |format|
format.html { redirect_to(#question) }
format.js
end
end
I'd think this would do the job
#question = current_user.questions.find params[:question_id]
if not, then just assign mannualy.
#site = #question.sites.build(params[:site])
#site.user = current_user
#site.save
I have a User Model(:name, :password, :email), and Event model(:name, :etc) and Interest model (:name) [>all singular<]
Then I created two join tables -> UsersInterests and EventsInterests; each not containing a primary key and only comprised of the user_id/interest_id and event_id/interest_id respectively. [>plural<]
My Models Use the Nested Has Many Through Plugin
user.rb => has_many :users_interests
has_many :interests, :through => :users_interests
has_many :events_interests, :through => :interests
has_many :events, :through => :events_interests
event.rb => has_many :events_interests
has_many :interests, :through => :events_interests
has_many :users_interests, :through => :interests
has_many :users, :through => :users_interests
interest.rb => has_and_belongs_to_many :users
has_and_belongs_to_many :events
events_interests.rb => belongs_to :interests
belongs_to :events
users_interests.rb => belongs_to :users
belongs_to :interests
Whew..ok So I wanted to created a named_scope of that find all the events that share interest with a particular user. Here is some code someone helped me with.
named_scope :shares_interest_with_users, lambda {|user|
{ :joins => :users_interests,
:conditions => {:users_interests => {:user_id => user}}
}}
When i run from the controller =>
#user = User.find(1)
#events = Event.shares_interest_with_user(#user)
I get the error :
uninitialized constant Event::EventsInterest
Can anyone see what i messed up?
You must have named something wrong along the way. At a glance I'd say you have a file or class named incorrectly. Remember model names MUST always be singular, both in file and class names or else Rails won't make the connection. Another source of your problem is that arguments to belongs_to must also be singular. Even if you had got things right, the HABTM relationship in interests with users would have thrown an error when you ran the named scope.
I was able to solve your error with the following models.
user.rb
class User < ActiveRecord::Base
has_many :users_interests
has_many :interests, :through => :users_interests
has_many :events_interests, :through => :interests
has_many :events, :through => :events_interests
end
users_interest.rb
class UsersInterest < ActiveRecord::Base
belongs_to :user
belongs_to :interest
end
interest.rb
class Interest < ActiveRecord::Base
has_many :users,:through => :users_interests
has_many :users_interests
has_many :events_interests
has_many :events, :through => :events_interests
end
**events_interest.rb
class EventsInterest <ActiveRecord::Base
belongs_to :interest
belongs_to :event
end
event.rb
class Event <ActiveRecord::Base
has_many :events_interests
has_many :interests, :through => :events_interests
has_many :users_interests, :through => :interests
has_many :users, :through => :users_interests
named_scope :shares_interest_with_users, lambda {|user|
{ :joins => :users_interests,
:conditions => {:users_interests => {:user_id => user}}
}
}
end