Rails 3.2 basic relationship has_many - ruby-on-rails-3

I've reread the rails guide to associations but still am hitting my head up against the wall. I've seen some advanced questions on Stack Overflow and am not able to determine if they shed light on my problem. Perhaps I've haven't gotten my mind wrapped around this. Please show me what I'm not seeing.
I have a School.rb which has_many Events, has_many Venues. Each of the Events and Venues belongs_to School. I'm trying to link up the Venue to an Event. They are tied to the school because they have a matching school_id. The name of the school is easily applied in Event#show and Venue#show as expected. The trick is how do I craft the Event controller to use the school_id to pull the Venue's addy in the Event#show page?
My attempts keep missing so I got to thinking maybe I have to make the Event belongs_to Venue and Venue has_many Events. Is that the right thing to do?
I attempt <%= #event.venue.address %> but that fails with 'undefined method `address' for nil:NilClass'
Maybe I'm overthinking it but as I mention above, I don't know enough to ask the right question. If I was to put my query in English terms it would be "Grab the instance of Venue whose school_id matches the school_id of the current/active Event." Does that make sense? I've attempted to find something close to that in the rails guides and attempted this:
#venues = Venue.where(:school_id => #school_id)
undefined method `address' for []:ActiveRecord::Relation. The venue address is in the venue model.
Here's my school.rb:
class School < ActiveRecord::Base
has_many :events, :dependent => :destroy
has_many :venues, :dependent => :destroy
has_and_belongs_to_many :users
belongs_to :event belongs_to :venue
def self.fetch_for_name(_name)
school = self.new(:name => _name)
end
end
Here's my event.rb:
class Event < ActiveRecord::Base
resourcify
belongs_to :school
belongs_to :venue
end
Here's my Venue.rb:
class Venue < ActiveRecord::Base
resourcify
belongs_to :school
has_many :events
end
Please help me get over this baby step, sam

You need to look at this part of the guide and ensure you have has_many through relationship between venue and events here as explained in the link...

To do the exact thing you are asking, you'd create a method in Venue to query for a given event.
class Venue < ActiveRecord::Base
resourcify
belongs_to :school
has_many :events
def self.venue_for_event(event)
where("school_id = ?", event.school_id)
end
end
However, there are some questions to be asked about your models. Why does a school have many events and venues yet also belong to one event and venue? What is the problem you are trying to solve with these models? If school is the glue that holds venues and events together, than consider making it a join model in a has_many, :through relationshuip

Related

Nested association query

Class User
has_many :universities
end
Class University
belongs_to :user
has_many :courses
end
Class Course
belongs_to :university
end
Now, I want to find the courses of any user.
I can use the following query:
User.find(1).universities.collect{|x| x.courses}
But is there any other simple ways to get this result? Please explain your answer so that I can understand.
Thanks in advance!
Add into User model:
has_many :courses, through: :universities
Now you can fetch all courses of a user via:
User.find(1).courses
From docs (http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association):
A has_many :through association is often used to set up a many-to-many connection with another model. This association indicates that the declaring model can be matched with zero or more instances of another model by proceeding through a third model.

Rails 3: Object chaining with has_many :through associations

I'm trying to get a grasp of how to work with associations in Rails, specifically, when and when not to write explicit SQL code.
In my application, I have four models, which are defined as follows:
class User < ActiveRecord::Base
has_many :comments
has_many :geographies
has_many :communities, through: :geographies
class Comment < ActiveRecord::Base
belongs_to :user
class Community < ActiveRecord::Base
has_many :geographies
has_many :users
class Geography < ActiveRecord::Base
belongs_to :user
belongs_to :community
Users can post comments, and are associated to one or more communities through the geography table (the geography table stores user_id and community_id).
I have an index action listing all comments, and I would like to filter by community. Given a comment object, I can get the user object via comment.user, but I can't chain beyond that (i.e., something like comment.user.geography(0).community doesn't work).
It seems this object chaining is a key feature of rails, but does it work with has_many :through associations? Given my example, is it possible to get the community object from the comment object by using object chaining, or would I need to write the SQL to get anything other than the user when given the comment object?
Since User is associated with multiple communities, you will need to tell ActiveRecord (or raw SQL) which community you want:
comment.user.communities #=> should give you all the communities
If you don't particularly care for getting all communities and just want to get any community
comment.user.communities.first #=> should give you the first community
But, generally you will be interested in one particular community, based on a condition.
comment.user.communities.where(name: 'Europe') #=> should give you the European community.
I don't think you need the geographies table.
Try
class Community < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
belongs_to :community
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :user
end
Then you can access a comment's user's community like
#comment.user.community

Rails 3 - associations

I print in my view a number that tell me, how many people read my article. It looks something like a:
<%=article.hits.count%>
As is possible to see, I created a simple association.
Now I am trying to get the information, if the user who is log in on my page, so if he is already had read this article. In my table that contains hits is column user_id.
But I can't still find the way, how to get...
I tried something like:
<% if session[:login_user_id].hits.user_id == session[:login_user_id]%>
Have you read it already.
<% end %>
But the example above doesn't work me... Could anyone help me please, how to do?
EDIT: The models:
class Article < ActiveRecord::Base
has_many :hits
end
class Hits < ActiveRecord::Base
belongs_to :article, :class_name => "DataHit", :foreign_key => "article_id"
has_many :users
end
class User < ActiveRecord::Base
belongs_to :hit
end
Thanks in advance
Let's first talk about the model you like to receive. For me, it sounds like:
Every article can be visited / read by many users.
Every user can read / visit many articles.
This is a classical n:m-association which is normally implemented by a has-many-through association.
If this is the intention, it should be implemented like:
class Article < ActiveRecord::Base
has_many :hits
has_many :users, :through => :hits
end
class Hits < ActiveRecord::Base
belongs_to :article, :class_name => "DataHit", :foreign_key => "article_id"
belongs_to :user
end
class User < ActiveRecord::Base
has_many :hits
has_many :articles, :through => :hits
end
Of course, you have to add migrations that ensure that the final DB model is like that:
Hit has article_id and user_id to ensure that users may find the articles they have read
If you have that model implemented, it should be more easy. Then you have operations available like: #article.users.contains(User.find(user_id)). Have a look at the tutorial at Ruby on Rails Guides which explain what the has-many-through relation is and which advantages they have.
It would be helpful if you try the things first in the console of Rails. To do that, start with:
Start the rails console in the root directory of your application: rails c
Enter there e.g.: art = Article.find(1) to get the article with the id.
Try which methods are available: art.methods.sort to see all methods that could be used. If there is no method users, you have did something wrong with the assocication.
Try the call: us = art.users and look at the result. It should be a rails specific object, an object that behaves like a collection and understands how to add and remove users to that collection (with the whole life cycle of rails). The error your currently have could mean different things:
Your database model does not match your associations defined in Rails (I suspect that).
Some minor tweak (misspelling somewhere) which hinders Rails.
I hope this gives you some clues what to do next, I don't think that we can fix the problem here once and for all times.

HABTM Polymorphic Relationship

I'm pretty new to Rails, and i'm trying to do a polymorphic HABTM relationship. The problem is that I have three models that I want to relate.
The first one is the Event model and then are two kind of attendees: Users and Contacts.
What I want to do is to be able to relate as an attendee both users and contacts. So, what i have right now in my code is:
Event Model
has_and_belongs_to_many :attendees, :polymorphic => true
User Model
has_and_belongs_to_many :events, :as => :attendees
Contact Model
has_and_belongs_to_may :events, :as => :attendees
How the HABTM table migration needs to be? I'm a little confused and i have found no help on that.
Is it going to work?
No, you can't do that, there's no such thing as a polymorphic has_and_belongs_to_many association.
What you can do is create a middle model. It would probably be something like this:
class Subscription < ActiveRecord::Base
belongs_to :attendee, :polymorphic => true
belongs_to :event
end
class Event < ActiveRecord::Base
has_many :subscriptions
end
class User < ActiveRecord::Base
has_many :subscriptions, :as => :attendee
has_many :events, :through => :subscriptions
end
class Contact < ActiveRecord::Base
has_many :subscriptions, :as => :attendee
has_many :events, :through => :subscriptions
end
This way the Subscription model behaves like the link table in a N:N relationship but allows you to have the polymorphic behavior to the Event.
Resolveu parcialmente.
It does solve the problem given the framework that we have at our disposal, but it adds "unnecessary" complexity and code. By creating an intermediary model (which I will call B), and given A -> B -> C being "A has_many B's which has_many C's", we have another AR Model which will load one more AR class implementation into memory once it is loaded, and will instantiate for the sole purpose of reaching C instances. You can always say, if you use the :through association, you don't load the B association, but then you'll be left with an even more obsolete model, which will only be there to see the caravan pass by.
In fact, this might be a feature that is missing from Active Record. I would propose it as a feature to add, since it has been cause of concern for myself (that's how I landed in this post hoping to find a solution :) ).
Cumprimentos

Building an active record with associations to two belongs_to relationships

Going back to an example I had previously asked about, I'll try and make this question as simple as possible.
Supposed I have User and Document models.
A User has_many Documents and a Document belongs_to a User. This relationship works fine today.
I want to introduce an Edits model that belongs_to a Document and belongs_to a User. The User can be any user, not necessary the one who created the document. With this new model, the Document now has_many :edits and the User has_many :edits.
So far it would look like:
# user.rb
class User < ActiveRecord::Base
has_many :edits
has_many :documents
end
# document.rb
class Document < ActiveRecord::Base
belongs_to :user
has_many :edits
end
# edit.rb
class Edit < ActiveRecord::Base
belongs_to :user
belongs_to :document
end
When I create a Document through a User, the association between the User and Document are fine in both directions (user.documents and document.user)
Now when I want to create an Edit, the edit should be against a Document but should also be associated with the user who generated the edit (edit.user).
When I'm building this in my RSpec tests I'm struggling to get the associations correct using the "standard" association methods. If I do #user.edits.build({...}) it will associate the user in the returned Edit object, but not the Document. Likewise when I do #document.edits.build({...}) it will associate the Document but not the User.
I supposed I could expose the user_id and post_id in the attr_accessible declaration but won't this but I fear this is not a best way of doing this. I have no real reason to fear other than the attributes are now accessible through mass assignment (from what I understand).
Am I going about this the wrong way or is there a better way to create and test all the associations?
class User < ActiveRecord::Base
has_many :edits, :through => :documents
has_many :documents
end