How to write a :within scope for a polymorphic relationship? - ruby-on-rails

I have a Location model, and other models have a belongs_to :locatable, polymorphic: true
So, something like a PlaceOfInterest might look like this:
class PlaceOfInterest < ApplicationRecord
belongs_to :user
has_one :location, as: :locatable
# how to do this part?
scope :within,
-> (latitude, longitude, radius_meters = 0) {
where(%{ST_Distance(lonlat, 'POINT(%f %f)') < %d} % [longitude, latitude, radius_meters]) # approx
}
end
How can I get the lonlat which exists on Location from PlaceOfInterest to write the :within scope?

I'm not sure I completely understand your model structure, but you should just be able to do a joins before the where. Note the joins(:location) and the column name locations.lonlat
class PlaceOfInterest < ApplicationRecord
belongs_to :user
has_one :location, as: :locatable
scope :within,
-> (latitude, longitude, radius_meters = 0) {
joins(:location).where(%{ST_Distance(locations.lonlat, 'POINT(%f %f)') < %d} % [longitude, latitude, radius_meters]) # approx
}
end

Related

Get id, name from master table - Ruby

The association is has follows
Company has_many company_commodities
CompanyCommodity belongs to Company
CompanyCommodity belongs to Commodity
Consider that company1 has an entry in the company_commodities table.
Now in the decorator file, i need to get the commodity name and id of that record.
I have implemented as follows.
company1 = Company.find(1)
arr = co.company_commodities.map(&:commodity).pluck(:name, :id)
arr.map { |a| { name: a[0], id: a[1] } }
This produces the output as
[{:name=>"Pharmaceuticals", :id=>25},
{:name=>"Medical Devices", :id=>26}]
Is there a cleaner way to do this? 
class Company < ApplicationRecord
has_many :company_commodities
has_many :commodities, through: :company_commodities
end
class CompanyCommodity < ApplicationRecord
belongs_to :commodity
belongs_to :company
end
company = Company.find(1)
# this returns the object you can access by arr.first.id, arr.first.name
arr = company.commodities.select(:name, :id)
# if you want to access as hash, usage: arr.first['id'], arr.first['name']
arr = company.commodities.select(:name, :id).as_json
You can get the commodities association by using through, then you can use select to filter the attributes.
Change the associations as below
class Company
has_many :company_commodities
has_many :commodities, through: :company_commodities
end
class CompanyCommodity
belongs_to :company
belongs_to :commodity
end
And query the records as
company1 = Company.find(1)
arr = co.commodities.pluck(:name, :id)
arr.reduce([]) { |array, el| array << [[:name, :id], el].to_h}

rails scope without associations

I have a model called "activos", I need to show only the records that are not associated with another model called "relactivo".
I've been trying this in the model: scope :ts, -> { includes(:relactivo).where(relactivo: { activo: nil}) }
this is my model "activos"
class Activo < ActiveRecord::Base
self.primary_key = "IdActivos"
scope :ts, -> { includes(:relactivo).where(relactivo: { activo: nil}) }
has_one :relactivo, class_name: "Relactivo", foreign_key: "Activo"
end
and my model "relactivo"
class Relactivo < ActiveRecord::Base
self.primary_key = "IdRow"
belongs_to :activo, class_name:"Activo", foreign_key: "Activo"
end
Try doing this for your scope:
class Activo < ActiveRecord::Base
self.primary_key = "IdActivos"
scope :ts, -> { joins('LEFT OUTER JOIN relactivos ON relactivos.IdActivos = activos.IdActivos WHERE relactivos.IdActivos IS null'))) }
has_one :relactivo, class_name: "Relactivo", foreign_key: "IdActivos"
end
See if this works, The custom primary/foreign key makes it a little strange but try this.

Rails 4 + Postgresql - Joins table with 2 conditions

I need to list Inputs that have Translations with language_id = 1 and dont have Translations with language_id = 2
My current scope is:
scope :language, -> (id){joins(:translations).where('translations.language_id = 1)}
Models:
class Input < ActiveRecord::Base
has_many :translations
has_many :languages, through: :translations
scope :language, -> (id) {joins(:translations).where('translations.language_id = 1')}
def translation_from_language(language)
self.translations.where(language: language).take
end
end
class Translation < ActiveRecord::Base
belongs_to :input
belongs_to :language
before_save :default_values
#Apenas para testar o scope de search
scope :search, -> (part) { where("LOWER(value) LIKE ?", "%#{part.downcase}%") }
# Se nao setar um input manualmente, irá criar um novo
def default_values
self.input ||= Input.create
end
end
class Language < ActiveRecord::Base
has_many :translations
has_many :inputs, through: :translations
end
So my solution is just create a query like
Input.where("id IN ( SELECT input_id
FROM translations
WHERE language_id = 1
)
AND id NOT IN (
SELECT input_id
FROM translations
WHERE language_id = 2
)")

How to define the scope?

I have:
price_plan.rb
class PricePlan < ActiveRecord::Base
has_many :users
scope :premium, lambda { where('price > ?', 0) }
scope :free, lambda { where('price == ?', 0) }
end
user.rb
class User < ActiveRecord::Base
belongs_to :price_plan
has_one :account
scope :free, lambda { joins(PricePlan.free) } #<--- no!
end
How to define scope for users, that use service free of charge?
This below should work, but I don't like it.
scope :free,-> where(priceplan_id: PricePlan.free.pluck(:id))
It will be
Solution 1: Use condition on relation
class User < ActiveRecord::Base
# Your current code
belongs_to :free_price_plan, -> { free }, class_name: 'PricePlan'
belongs_to :premium_price_plan, -> { premium }, class_name: 'PricePlan'
end
Solution 2: Define a scope
class User < ActiveRecord::Base
# Your current code
scope :free, -> {
joins(:price_plan).merge(PricePlan.free)
}
scope :premium, -> {
joins(:price_plan).merge(PricePlan.premium)
}
end

Rails filtering resource one to many through a joint table

I have the following resources:
- restaurant
- category
- item
- check item
Relationship:
class Restaurant < ActiveRecord::Base
has_many :items
has_many :categories
has_many :check_items
class Category < ActiveRecord::Base
belongs_to :restaurant
has_many :items
class Item < ActiveRecord::Base
belongs_to :restaurant
belongs_to :category
class CheckItem < ActiveRecord::Base
belongs_to :item
I need to filter all the check_items of a restaurant where category.uuid = '123123'
so I have my #restaurant.check_items. How do I join these together to basically implement this sql query:
SELECT * from checkitem
INNER JOIN item ON(checkitem.item_id = item.id)
INNER JOIN category ON(category.id = item.category_id)
WHERE category.restaurant_id = 1 AND category.uuid = '123123'
LIMIT 20;
I've tried with scope:
#already have my restaurant resource here with id 1
#restaurant.check_items.by_item_category params[:category_uuid]
And in my models I would have:
class CheckItem < ActiveRecord::Base
...
scope :by_item_category, -> value { joins(:item).by_category value }
class Item < ActiveRecord::Base
...
scope :by_category, -> value { joins(:category).where('%s.uuid = ?' % Category.table_name, value)}
Buut this doesn't seem to work
This appears to be the only way I found this to be working if anyone is interested.
CheckItem.joins(:item => {:category => :restaurant}).where('category.uuid=? and restaurant.id=?', 123123, 1)

Resources