knygw
knygw

Reputation: 382

Rails Controller Variables and Complex Relationships

Let's say we have the following scenario in a Rails application:

Users have many Websites, and Websites have many Simulations (likewise, Websites belong to Users, and Simulations belong to Websites).

Now the problem is, how do I display a list of all of a User's Simulations on the User Show page?

My first gut attempt was to define the following in the Users Controller:

def show
  @user = User.find(params[:id])
  @websites = @user.websites
  @simulations = @user.websites.simulations
end

And then use <%= render @simulations %> in the Users Show Page, but that gives a NoMethodError: undefined methodsimulations' for []:Array` when I visit localhost:3000.

So how can I create a variable in my User Controller that holds all the Simulations that belong to the Websites that belong to a particular User?

Any and all help is greatly appreciated!

Upvotes: 1

Views: 161

Answers (3)

Kevin Wang
Kevin Wang

Reputation: 3330

Use Erez's answer


You asked for it - I don't know about ruby, but each website in @websites should already contain a field that has a simulation.

This is what you're doing.

1 - You take user, a single object, and get its websites. Cool. User looks something like this (in pseudocode):

 Object @user
    {
         Array[] websites = [(Website)site1, (Website)site2];
    } 

Alright, that's cool. So user.websites should return an array of websites.

2 - You try to get the simulations from a website. A website probably looks like this:

 Object @website
    {
         Array[] simulations = [(Simulation)sim1, (Simulation)sim2];
    } 

Hm, why doesn't it work? Well lets break down what you're doing:

@user.websites.simulations

You're taking websites, which is an array, and trying to reference a variable that belongs to a website type and not an array type. @user.websites is an array object that holds websites, not a website itself. What you want is to get @website.simulations, not websites.simulations.

So the first step is getting a website. That's easy - one way would be to try to fetch a website from your website array in the user.

@User.websites[0] <-- may not be syntactically correct; I don't know ruby.

Now if you want to get all of the websites, iterate through them using a loop and push them to a new array. Again in pseudocode:

@all_simulations = new Array();
for(@i=0;@i<count(@user.websites);@i++) //first loop through the websites
{
     for(@q=0;@q<count(@user.websites[@i].simulations);@q++) //then loop through the simulations
     {
           @all_simulations.push(@user.websites[@i].simulations[@q]); //push the simulation into @all_websites
     }
}

What we do here is we go into each website in the user.websites array and then grab each simulation from that website and throw that into our @all_simulations variable. If you understand the concept, you should be able to convert this logic into valid ruby.

Upvotes: 0

Erez Rabih
Erez Rabih

Reputation: 15788

class User < ActiveRecord::Base
  has_many :websites
  has_many :simulations, :through => :websites
end

now you can use @simulations = @user.simulations and get all the user's simulations

Upvotes: 2

Ismael
Ismael

Reputation: 16730

In your user model add this method. This will produce 2 queries but still better then joining simulations in ruby code.

def websites_simulations
  Simulation.where(website_id: website_ids)
end

Upvotes: 0

Related Questions