How do I join records together and seperate them with "-" - ruby-on-rails-3

I want to join records together and separate them with "-"
I know how to join one table records together like this:
#keywords = #tweet.hash_tags.join("-")
But what if it's HABTM associated tables.
For example.
// BRAND MODEL
has_and_belongs_to_many :categories
// CATEGORY MODEL
has_and_belongs_to_many :brands
If I do this:
#brands = Brand.all
#brand_categories = #brands.categories.join("-")
I get this result:
#<Category:0x0000010445c928>,#<Category:0x0000010445c7c0>,#<Category:0x0000010445c5e0>,#<Category:0x0000010445c400>,#<Category:0x0000010445c270>
Hope you understand my question - thanks.

#join will call #to_s on the items in the Array returned by #brands.categories by default, and it doesn't look like you've defined a custom Category#to_s. Either do so, or be more explicit about the string representation you want; if, for example, a Category has a title attribute, you could use:
#brands_categories = #brands.categories.map(&:title).join("-")

Assuming your Category table has a name field:
#brand_categories = #brands.categories.collect(&:name).join("-")
This will put all of the name values into an array, and then join those.

Related

Rails, order by same-named column on two different tables

I have a model Leagues::FantasyPlayer which has a polymorphic variable player_entity which is either a Players::NflPlayer or Players::TeamPlayer.
I'm attempting to load a league's fantasy players, sorted by "average_draft_position." Both tables Players::NflPlayer and Players::TeamPlayer have a column "average_draft_position."
Here is my current attempt:
fantasy_players = paginate Leagues::FantasyPlayer.includes(player_entity: :team).
joins("LEFT JOIN players_nfl_players ON leagues_fantasy_players.player_entity_id = players_nfl_players.id AND leagues_fantasy_players.player_entity_type = 'Players::NflPlayer'").
joins("LEFT JOIN players_team_players ON leagues_fantasy_players.player_entity_id = players_team_players.id AND leagues_fantasy_players.player_entity_type = 'Players::TeamPlayer'").
where(available: true, conference_id: conference_id,league_id: league_id).
order("players_nfl_players.average_draft_position, players_team_players.average_draft_position"), per_page: 15
The problem is that this returns the Players::NflPlayer table sorted by average_draft_position first, and then Players::TeamPlayer table sorted be average_draft_position afterwards - is there some way I can have the results from the two different tables interleaved?
Thank you!!
This should do the trick.
.order('COALESCE(players_nfl_players.average_draft_position, players_team_players.average_draft_position) DESC')

Rails ignores columns from second table when using .select

By example:
r = Model.arel_table
s = SomeOtherModel.arel_table
Model.select(r[:id], s[:othercolumn].as('othercolumn')).
joins(:someothermodel)
Will product the sql:
`SELECT `model`.`id`, `someothermodel`.`othercolumn` AS othercolumn FROM `model` INNER JOIN `someothermodel` ON `model`.`id` = `someothermodel`.`model_id`
Which is correct. However, when the models are loaded, the attribute othercolumn is ignored because it is not an attribute of Model.
It's similar to eager loading and includes, but I don't want all columns, only the one specified so include is no good.
There must be an easy way of getting columns from other models? I'd preferably have the items return as instances of Model than simple arrays/hashes
When you do a select with joins or includes, you will be returned an ActiveRecordRelation. This ActiveRecordRelation is composed of only the objects of the class which you use to call select on. The selected columns from the joined models are added to the objects returned. Because these attributes are not Model's attribute they don't show up when you inspect these objects, and I believe this is the primary reason for confusion.
You could try this out in your rails console:
> result = Model.select(r[:id], s[:othercolumn].as('othercolumn')).joins(:someothermodel)
=> #<ActiveRecord::Relation [#<Model id: 1>]>
# "othercolumn" is not shown in the result but doing the following will yield correct result
> result.first.othercolumn
=> "myothercolumnvalue"

Django - Making a SQL query on a many to many relationship with PostgreSQL Inner Join

I am looking for a perticular raw SQL query using Inner Join.
I have those models:
class EzMap(models.Model):
layers = models.ManyToManyField(Shapefile, verbose_name='Layers to display', null=True, blank=True)
class Shapefile(models.Model):
filename = models.CharField(max_length=255)
class Feature(models.Model):
shapefile = models.ForeignKey(Shapefile)
I would like to make a SQL Query valid with PostgreSQL that would be like this one:
select id from "table_feature" where' shapefile_ezmap_id = 1 ;
but I dont know how to use the INNER JOIN to filter features where the shapefile they belongs to are related to a particular ezmap object
Something like this:
try:
id = Feature.objects.get(shapefile__ezmap__id=1).id
except Feature.DoesNotExist:
id = 0 # or some other action when no result is found
You will need to use filter (instead of get) if you want to deal with multiple Feature results.

Query that joins just a single row from a ForeignKey relationship

I have the following models (simplified):
class Category(models.model):
# ...
class Product(models.model):
# ...
class ProductCategory(models.Model):
product = models.ForeignKey(Product)
category = models.ForeignKey(Category)
# ...
class ProductImage(models.Model):
product = models.ForeignKey(Product)
image = models.ImageField(upload_to=product_image_path)
sort_order = models.PositiveIntegerField(default=100)
# ...
I want to construct a query that will get all the products associated with a particular category. I want to include just one of the many associated images--the image with the lowest sort_order--in the queryset so that a single query gets all of the data needed to show all products within a category.
In raw SQL I would might use a GROUP BY something like this:
SELECT * FROM catalog_product p
LEFT JOIN catalog_productcategory c ON (p.id = c.product_id)
LEFT JOIN catalog_productimage i ON (p.id = i.product_id)
WHERE c.category_id=2
GROUP BY p.id HAVING i.sort_order = MIN(sort_order)
Can this be done without using a raw query?
Edit - I should have noted what I've tried...
# inside Category model...
products = Product.objects.filter(productcategory__category=self) \
.annotate(Min('productimage__sort_order'))
While this query does GROUP BY, I do not see any way to (a) get the right ProductImage.image into the QuerySet eg. HAVING clause. I'm effectively trying to dynamically add a field to the Product instance (or the QuerySet) from a specific ProductImage instance. This may not be the way to do it with Django.
It isn't quite a raw query, but it isn't quite public api either.
You can add a group by clause to the queryset before it is evaluated:
qs = Product.objects.filter(some__foreign__key__join=something)
qs.group_by = 'some_field'
results = list(qs)
Word of caution, though: this behaves differently depending on the db backend.
catagory = Catagory.objects.get(get_your_catagory)
qs = Product.objects.annotate(Min('productimage__sortorder').filter(productcategory__category = catagory)
This should hit the DB only once, because querysets are lazy.

Select distinct active record

I have a model called Shops with an attribute called brands, brands is a text field and contains multiple brands. What i would like to do is select all unique brands and display them sorted in alphabetic order
#brands = Shop.all(:select => 'distinct(brands)')
What to do from here?
If Shop#brands can hold multiple values like for example: "rony, hoke, fike", then I can reluctantly suggest doing something like this:
#brands = Shop.all(:select => 'brands').each { |s|
s.brands.split(',').map { |b|
b.strip.downcase
}
}.flatten.uniq.sort
BUT, you should really think about your data model here to prevent such hackery. You couuld break out the brands into it's own table + model and do a many to many relationship with Shop.