Ask A Question

Notifications

You’re not receiving notifications from this thread.

Pull data from another table in a lookup

Alan Reid asked in Rails

Hi all,
I am looking up a list of articles, depending on the brand ID's - @articles = Article.where(brand_id: brand_ids) what i would like to know is there a way to retrieve the brand name in this look up too so i don't have to do it later.

Maybe so it returns the article details + the brand name rather than the brand ID

Many thanks

Reply

This may not be the best way, but usually when I do this kind of stuff I use the controller to build an array that has all my data in it that I need for the view. Is there an association between articles and brands? If so you could use includes(:brands)

@articles = Article.where(Brand_id: brand_ids).includes(:brands).map { |article| [article.details, article.brands] }

I'm assuming with the plural 'brands' that an article could have many brands. So in the above example, @articles.first[1] would list all the associated brands with the first article.

Reply

I can't seem to get that to work.

Basically @articles = Article.where(brand_id: brand_ids) returns a list of articles which have a brand_id.

What i want to do is use that brand_id to get the name of the brand from the brands table and return it as part of @articles at present i then need to look up the brand id within the article, using
<%= Brand.find(article.brand_id).name %>
and obviously as we get more articles this could have loads of DB calls which is not ideal haha :)

Reply

I believe you want @articles = Article.where(brand_id: brand_ids).includes(:brand) which will load that association. Pretty close to what Jacob said, but you need to reference the association in the includes.

Then when you print out the articles, you can say

<% @articles.each do |article| %>
  <div>
    <%= article.brand.name %>
  </div>
<% end %>

This should be efficient because it will make two queries and preload the brand association on each article.

Reply

Whoops, looks like I had a few typos in there, sorry about that! I was however thinking the includes needed to be the plural form of the association but looking back at my own project it's indeed singular!

Do what Chris said and you'll be set! :)

Reply

haha Cheers guys :) Not to worry Jacob, thanks for your help mate, you made it easier for Chris really ;)

Reply

Jacob's the one that did the hard work though. I just had to tweak his answer a little bit. ;) He's the one that deserves cake 🍰.

Reply

See this is why I love this site. The community is fantastic!

Reply

Haha, yes this really is a great little community! :)

Reply

To clean this up, you may want to create a scope on article which performs all the joins and association loading. Would allow you to clean up the controller a bit and just says Article.method (where method is your AR query. Good practice to try to keep as much code out of the controller as possible, but Chris' answer will definitely get you what you need. I'd just suggest moving this to the model.

Reply

James you have a article i could look at regarding this?

Reply

I don't agree with that. Code in your controller isn't magically a bad thing. It's only a bad thing when it becomes overly complex. Having one query in your controller is actually a requirement for this method. If you extract it out, you still have to save the query in the controller but now you've hidden away the actual query which actually makes this more complicated with no benefit. Making a method arbitrarily to "clean up the controller" isn't actually a good reason to do this.

A good reason to refactor is if if you are using this query multiple places in the app and want to keep them consistent with each other. In that case, then yes, you do get value from abstracting this because you can change the functionality of each use of it all in one place.

class Article < ActiveRecord::Base
  def self.with_brands(brand_ids)
    scoped.where(brand_id: brand_ids).includes(:brand)
  end
end
# controller
@articles = Article.with_brands(brand_ids)
Reply

Alan, check:

http://tomdallimore.com/blog/includes-vs-joins-in-rails-when-and-where

https://gorails.com/blog/activerecord-merge

http://guides.rubyonrails.org/active_record_querying.html#scopes

I believe this should get you down the right rabbit hole. I'd have to dink around with your models to get something more concrete, I can't recall if I've ever done an includes in a scope. If you come up with a working scope please share if you can!

Reply

Chris is right, I just have a bad habit of hiding away complex queries into models. I think I wrongly assumed that this query was being used in multiple places as you suggested. Then yes, it's definitely of value to abstract it. But I do have a nasty habit of hiding things in models when I shouldn't. Got to work on that.

Reply

So that's how it would be done - thank you for the example Chris!

Here lately I've been refactoring things down like James had suggested in an attempt to better understand how each entity in the MVC framework really works together. Even if it's overkill or unnecessary, I think it's been an incredible learning experience! The hard part is once you know how to abstract/refactor things out, when to do it and when not to do it...

Reply

Guys thank you all so much for the extended discussion on this topic. Its really useful, and nice again more learning for me :D.

I have started to use it a lot else where in the site so it could be useful to have some of the lookups like this. I can also use this elsewhere in the app for other lookups.

Chris's example would work really well for me as I am using a similar lookup for users who don't manage the brands, but only follow them. So i could in theory retrieve articles for both there :)

Reply

Chris, we really need a like or kudos button you solved my issue, but others provide some great input too so they should get rewarded as well ;)

Reply

That's a feature I was literally just starting to write tonight. :)

Reply

Chris,
I am trying to get this to include product details too, like we did above but for some reason i can't get it to work :/ could you see what i am missing please?

I am Getting a list the items in a backbar, which works fine, until i add in the includes() bit to get the extra details. I really can't get my head around includes(). lol

@products = BackBar.where(:venue_id => @venue.id).includes(:product)

This @products = BackBar.where(:venue_id => @venue.id) returns a list of items which are in the BackBar table, in there are 2 fields which are referenced venue_id and product_id -- Returns id: 1, venue_id: 1, product_id: 5

class BackBar < ApplicationRecord
  belongs_to :product
  has_many :venues

end
class Product < ApplicationRecord
  has_many :back_bars

end
class Venue < ApplicationRecord
  belongs_to :back_bar
end
Reply

If I'm not mistaken, your association is wrong. class BackBar would need has_many :products in order to use .includes() like this.

Check out http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations and http://apidock.com/rails/ActiveRecord/QueryMethods/includes for some extra details on includes.

I think you need to fix your association to something more like this:

class BackBar < ApplicationRecord
  has_many :products
  has_many :venues
end

class Product < ApplicationRecord
end

This would allow you to do something like:

@products = Backbar.where(:venue_id => @venue.id).includes(:product)

or if you just need the products that go with that backbar, then

@products =  Backbar.where(:venue_id => @venue.id).products
Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 85,376+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.