In Ruby I can sort some objects by invoice number in descending order like:
#app.sample_sales.sort_by {|sale| -sale.payload['invoice_number'].to_i }
However I can't quite get it to work using Rails:
#app.sample_sales.order("payload->'invoice_number' desc")
I've also tried:
#app.sample_sales.order("payload->'invoice_number::integer' desc")
Models
#sample_app.rb
class SampleApp < ApplicationRecord
has_many :sample_sales, dependent: :destroy
end
#sample_sale.rb
class SampleSale < ApplicationRecord
belongs_to :sample_app
end
Your syntax is not correct. Here is a good one:
#app.sample_sales.joins(:payload).order('payload.invoice_number desc')
I might update this answer when you've shared your model's associations. 😉
Related
I have two models
class Category < ActiveRecord::Base
has_many :products
end
class Product < ActiveRecord::Base
has_many :photos
belongs_to :category
def self.similar(product)
where("name LIKE ?", "#{product.name}%").limit(4)
end
end
I would like the self.similar method to product products which are similar to the argument passed to it(product).
The trouble Im having is that this method only returns products which match the argument perfectly. Im wondering if its possible to set the tolerance of this method to product a broader range of products rather than ones which match the argument perfectly? Or perhaps another superior way to produce an array of similar products.
You must simple change your where query to following:
def self.similar(product)
where("name LIKE ?", "%#{product.name}%").limit(4)
end
and your LIKE query should work..with the % at the start and the end also not exactly matching results will be returned..
If you don't want to/can't install a gem, then you can use Postgres' levenshtein (if it's installed):
Model.select("*, levenshtein(LOWER(name) , '#{thing_name.downcase}') AS fuzzydist").order('fuzzydist ASC').first
I had a very good experience using fuzzy_match. There is no built in ActiveRecord nor Rails nor Ruby support for it otherwise.
So your code would then become more or less
require 'fuzzy_match'
class Category < ActiveRecord::Base
has_many :products
end
class Product < ActiveRecord::Base
has_many :photos
belongs_to :category
def self.similar(product)
fz = FuzzyMatch.new(Product.all, :read => :name)
return fz.find(product.name).limit(4)
end
end
Not new to Ruby on Rails, but never really worked with more complicated ActiveRecord queries.
Say I have a Affiliate model that has_many referred users and referred users has_many purchased_products.
What I want to do is an efficient ActiveRecord way of getting the total sum of the count of purchased_products of all the referred users. How do I go about doing this?
Thanks.
Assuming objects like:
class Affiliate < ActiveRecord::Base
has_many :users
end
class Users < ActiveRecord::Base
#should have purchased_products_count integer column
belongs_to :affiliate
has_many :pruchased_products
end
class PurchasedProducts < ActiveRecord::Base
belongs_to :user, counter_cache: :purchased_products_count
end
products_count = User.first.purchased_products.size # uses counter_cache to get the size
another_products_count = User.first.purchased_products_count # get the value diretly
all_users_products_count = my_affiliate.users.map(&:purchased_products_count).inject(:+) # makes an array of product counts then sums them
I think this might also work
my_affiliate.users.sum('purchased_products_count')
I have 3 models:
class ProductLine < ActiveRecord::Base
has_many :specifications
has_many :specification_categories, :through => :specifications,
end
class Specification < ActiveRecord::Base
belongs_to :product_line
belongs_to :specification_category
end
class SpecificationCategory < ActiveRecord::Base
has_many :specifications
has_many :product_lines, :through => :specifications
end
Basically, we are showing the specifications as a subset of data on the product line page and we would like to do something like (example only, yes I'm aware of N+1):
Controller:
#product_line = ProductLine.find(params[:id])
#specification_categories = #product_line.specification_categories)
View:
#specification_categories.each do |specification_category|
...
specification_category.specifications.each do |specification|
...
end
end
The issue here is getting rails to filter the specifications by ProductLine. I've tried constructing queries to do this but it always generates a separate NEW query when the final association is called. Even though we aren't using the code above now (not a good idea here, since we could potentially run into an N+1 problem), I'd like to know if it's even possible to do a 3 way join with association filtering. Has anyone run across this scenario? Can you please provide an example of how I would accomplish this here?
Prevent the N+1 by altering your line to:
#specification_categories = #product_line.specification_categories).include(:specifications)
OR
Construct your own query using .joins(:association), and do the grouping yourself.
I want to create a random pack of 15 cards which should be invoked in the cardpacks_controller on create. I have the following models:
Card:
class Card < ActiveRecord::Base
# relations
has_many :cardpacks, through: :cardpackcards
belongs_to :cardset
end
Cardpack:
class Cardpack < ActiveRecord::Base
#relations
has_many :cards, through: :cardpackcards
belongs_to :cardset
# accept attributes
accepts_nested_attributes_for :cards
end
Cardpackcards:
class Cardpackcard < ActiveRecord::Base
#relations
belongs_to :card
belongs_to :cardpack
end
Cardsets:
class Cardset < ActiveRecord::Base
#relations
has_many :cards
has_many :cardsets
end
How can I create 15 Cardpackcards records with random card_id values and with the same cardpack_id (so they belong to the same pack)
I have watched the complex form series tutorial but it gives me no comprehension as how to tackle this problem.
I hope anyone can help me solve this problem and give me more insight in the rails language.
Thanks,
Erik
Depending on the database system you might be able to use an order random clause to find 15 random records. For example, in Postgres:
Model.order("RANDOM()").limit(15)
Given the random models, you can add a before_create method that will setup the associations.
If the Cardpackcard model doesn't do anything but provide a matching between cards and cardpacks, you could use a has_and_belongs_to_many association instead, which would simplify things a bit.
Without it, the controller code might look something like this:
cardset = Cardset.find(params[:cardset_id])
cardpack = Cardpack.create(:cardset => cardset)
15.times do
cardpack.cardpackcards.create(:card => Card.create(:cardset => cardset))
end
Im very new to Ruby on Rails 3 and ActiveRecord and seem to have been thrown in at the deep end at work. Im struggling to get to grips with querying data from multiple tables using joins.
A lot of the examples Ive seen either seem to be based on much simpler queries or use < rails 3 syntax.
Given that I know the business_unit_group_id and have the following associations how would I query a list of all related Items and ItemSellingPrices?
class BusinessUnitGroup < ActiveRecord::Base
has_many :business_unit_group_items
end
class BusinessUnitGroupItem < ActiveRecord::Base
belongs_to :business_unit_group
belongs_to :item
belongs_to :item_selling_price
end
class Item < ActiveRecord::Base
has_many :business_unit_group_items
end
class ItemSellingPrice < ActiveRecord::Base
has_many :business_unit_group_items
end
I'm confused as to whether I need to explicity specify any joins in the query since the associations are in place.
Basically, you do not need to specify the joins:
# This gives you all the BusinessUnitGroupItems for that BusinessUnitGroup
BusinessUnitGroup.find(id).business_unit_group_items
# BusinessUnitGroupItem seems to be a rich join table so you might
# be iterested in the items directly:
class BusinessUnitGroup < ActiveRecord::Base
has_many :items through => :business_unit_group_items
# and/or
has_many :item_selling_prices, through => :business_unit_group_items
...
end
# Then this gives you the items and prices for that BusinessUnitGroup:
BusinessUnitGroup.find(id).items
BusinessUnitGroup.find(id).item_selling_prices
# If you want to iterate over all items and their prices within one
# BusinessUnitGroup, try this:
group = BusinessUnitGroup.include(
:business_unit_group_item => [:items, :item_selling_prices]
).find(id)
# which preloads the items and item prices so while iterating,
# no more database queries occur