Jump to content

The ultimate community for Ruby on Rails developers.


Photo

Accessing data thru join table


  • Please log in to reply
7 replies to this topic

#1 dcastellano1

dcastellano1

    Signalman

  • Members
  • 13 posts
  • LocationColumbus, Ohio

Posted 25 November 2013 - 11:51 AM

Hi,

 

I am still an inexperienced programmer and am trying to figure out how to access data associated thru a join table.  My understanding is that it can be accessed like other attribute but I have been unable to do so. Here is what I am trying to do...

 

I have the following hash (@minisections):

 @minisections
=> [[#<Minisection id: 2, title: "Epithelial Keratitis", subsection_id: 1, about: nil, order_list: nil, created_at: "2012-11-24 17:44:38", updated_at: "2012-11-24 17:44:38">,
  #<Minisection id: 18, title: "Stromal Keratitis", subsection_id: 1, about: nil, order_list: nil, created_at: "2013-04-01 01:47:11", updated_at: "2013-04-01 01:47:11">,
  #<Minisection id: 19, title: "Bugs", subsection_id: 1, about: nil, order_list: nil, created_at: "2013-04-24 23:44:46", updated_at: "2013-04-24 23:44:46">,
  #<Minisection id: 20, title: "Test Gallery", subsection_id: 1, about: nil, order_list: nil, created_at: "2013-06-06 00:25:57", updated_at: "2013-06-06 00:25:57">,
  #<Minisection id: 3, title: "Disciform Keratitis", subsection_id: 1, about: nil, order_list: nil, created_at: "2012-12-27 20:26:53", updated_at: "2013-07-19 17:41:36">]]
 
Each row (minisection) has associated pictures through the join table "minisections_pictures".
 
I am trying to create a hash (@pictures) containing each minisection and its associated pictures.
 
I have tried several ways including the following:
 
t=0
@pictures = Array.new
@minisections.each do |minisection|
     @pictures[t] = minisection.pictures
end
t=t+1

 

Any help would be appreciated.

 

Dave



#2 Ohm

Ohm

    Guard

  • Members
  • 179 posts
  • LocationCopenhagen

Posted 25 November 2013 - 03:15 PM

What errors do you get?

 

You do realise that your @minisections is an array of arrays? (You have two [ at the beginning)


Blog: http://ohm.sh | Twitter: madsohm


#3 dcastellano1

dcastellano1

    Signalman

  • Members
  • 13 posts
  • LocationColumbus, Ohio

Posted 25 November 2013 - 05:37 PM

You do realise that your @minisections is an array of arrays? (You have two [ at the beginning)

 

This is how I am creating the @minisections array (I believe this is setting each minisection to its own array within the @minisections array):

 

r=0
@minisections = Array.new
@subsections.each do |subsection|
     if !subsection[r].minisections.blank?
         @minisections[r] = subsection[r].minisections
     end
r=r+1
end

 

Should it not be an array of arrays?

 

What errors do you get?

 

If I try:

t=0
@pictures = Array.new
@minisections.each do |minisection|
    @pictures[t] = minisection.pictures
     t=t+1
end

 

I get:

NoMethodError (undefined method `pictures' for #<ActiveRecord::Relation:0x007fc2a21ab1b8>)

 

 

And if I try:

t=0
@pictures = Array.new
@minisections.each do |minisection|
    @pictures[t] = Minisection.find(minisection).pictures
     t=t+1
end

 

I get:

TypeError (Cannot visit Minisection):
  app/controllers/dropdowns_controller.rb:60:in `block in update_image_subject'
  app/controllers/dropdowns_controller.rb:58:in `each'
  app/controllers/dropdowns_controller.rb:58:in `update_image_subject'


#4 Ohm

Ohm

    Guard

  • Members
  • 179 posts
  • LocationCopenhagen

Posted 25 November 2013 - 06:41 PM

I like your gumption Dave.

 

Okay. So it seems like you are trying to get a hash where the keys are an increasing number and the values are an array of pictures. I assume that your two models are something like:

class Minisection < ActiveRecord::Base
  has_many :pictures
end

class Picture < ActiveRecord::Base
  belongs_to :minisection
end 

With this we are able to grab the pictures for the first Minisection in our database with:

Minisection.first.pictures

Wanting instead all the Minisections and their corresponding pictures, we can use #map, which applies a method to all elements in an array. Lets first grab all Minisections:

@minisections = Minisection.all

Now we can apply the picutres-method to all of them with map

@minisections.map(&:pictures)

We now have all Pictures for all Minisections.

 

---

 

With regards to your case, the reason I was asking about array of arrays is that there doesn't seem to be a reason for it. You just have an array surrounding an array of Minisections. The outer array only have that one entry, which is the inner array. 

 

You might want to do it something like this instead, when collecting the Minisections from the Subsections:

@minisections = subsections.map(&:minisections).compact

Here #compact removes the nil values, that is the Subsections without Minisections.


Blog: http://ohm.sh | Twitter: madsohm


#5 dcastellano1

dcastellano1

    Signalman

  • Members
  • 13 posts
  • LocationColumbus, Ohio

Posted 26 November 2013 - 02:55 AM

Ok, so the array within an array WAS a problem.  Thanks for pointing it out.  Now I am trying to fix it and have made it a single array but have a more basic problem I think.

 

n=0
@chapters = Array.new
@books.each do |book|
    @chapters[0,n] = book.chapters
    n=n+1
end
 
This only adds the last chapter of each book to the array (I'm assuming it is overwriting the chapters in each book until the last one), so I end up with only 1 chapter (the last) for each book.
I see the problem, needing to loop thru the chapters and increase the @chapters counter each time but can't figure out how. Can you point me in the right direction?
 
By the way, how are you putting your code examples into the text fields with a surrounding border?  It really looks good and is easy to follow.
 
Thanks again,
 
Dave


#6 Ohm

Ohm

    Guard

  • Members
  • 179 posts
  • LocationCopenhagen

Posted 26 November 2013 - 06:21 AM

I'm in a bit of a hurry, so can't give you a precise answer, however you might want to look at this blog post from Thoughtbot: http://robots.though...n-anti-pattern/


Blog: http://ohm.sh | Twitter: madsohm


#7 dcastellano1

dcastellano1

    Signalman

  • Members
  • 13 posts
  • LocationColumbus, Ohio

Posted 26 November 2013 - 04:43 PM   Best Answer

Thanks Ohm!

 

@pictures = []
@minisections.each do |minisection|
    @pictures << minisection.pictures
end
@pictures.flatten!
 
 
 


#8 Ohm

Ohm

    Guard

  • Members
  • 179 posts
  • LocationCopenhagen

Posted 26 November 2013 - 04:57 PM

You are welcome.

 

Just so you know, it's more Rubyish to do it like

@picutres = @minisections.map(&:pictures).flatten

Avoiding the #each call and the block when it isn't necessary. The flatten is still needed as each #pictures call return an array and you want the flatten 1d array.

 

---

 

The way we arrive at the above is also interesting. Let me concatenate things:

@pictures = []
@minisections.each do |minisection|
  @pictures << minisection.pictures
end
@pictures.flatten! 

is the same as doing

@pictures = []
@minisections.each {|m| @pictures << m.pictures }
@pictures.flatten! 

which is the same as

@pictures = @minisections.inject([]) {|arr, m| arr << m.pictures }.flatten 

Here we inject the empty array into our function always returning the result as the next arr. That is, take the empty array. Let this be arr. Append m. Return the array with m appended as arr. Continue.

 

This is the same as

@pictures = @minisections.collect {|m| m.pictures }.flatten 

#collect and #map are synonyms. Instead of a block, #map can take a Proc (a method) we can thus call the #pictures method on each element, without naming each element m.

@pictures = @minisections.map(&:pictures).flatten 

Et voilĂ . Nice Ruby code.


Blog: http://ohm.sh | Twitter: madsohm





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users