I have 2 models parent child. I need all child of parent in child model when child has where condition.
class Parent
has_many :children
end
class Child
belongs_to :parent
end
I am getting data in child model like
id: 1
parent_id: 1
date: 2022-09-22
id: 2
parent_id: 1
date: 2022-09-23
id: 3
parent_id: 2
date: 2022-09-24
from Child.where(date: from_date..to_date) and this condition is coming from controller. Now I need one more field here child.parent.child.all in every record. This field is showing wrong data. it is showing data only within selected date range.
i.e. from above example from_date: 2022-09-22 and to_date: 2022-09-24 and parent_id: 2 have 4 child but in given date range it is showing only 1 because only 1 child data is falling in the given date range. but i need 4.
Thanks
Related
I have an Invoice and Order model with the following relationship:
class Invoice < ApplicationRecord
has_many orders
end
class Order < ApplicationRecord
belongs_to invoice
end
In my Invoice model, I am trying to loop through the orders belonging to an invoice using collect. An extra order with nil attributes is being added to my results.
orders.collect{|order| order}
Results:
[#<Order id: 1, menu_item_id: 1, invoice_id: 1, quantity: 1, status: "Submitted", created_at: "2020-05-25 15:48:25", updated_at: "2020-05-25 15:48:25">,
#<Order id: nil, menu_item_id: nil, invoice_id: 1, quantity: nil, status: nil, created_at: nil, updated_at: nil>]
I have checked the existence of this blank item in the database but I am not seeing anything.
Edit:
Fixed this by removing an unnecessary instance.order.build in my controller. Thanks to #3limin4t0r for bringing this up
Things don't magically appear. If there is an empty record in your orders collection, you've probably added it somewhere to the collection.
Things like:
invoice.orders.build
invoice.orders.new
invoice.orders << Order.new
All add an empty order to the orders collection. These actions are commonly found inside the controller new and create actions, but can also appear in other places.
Once a collection like invoice.orders is loaded it will stay loaded for the duration of the request (as long as invoices is in scope and you're working on the same invoice instance).
The best thing to do is look where you've added this additional instance to the collection and remove the statement if possible. Alternatively you can reload the collection from the database with invoice.orders.reload resetting the orders collection.
We have several models that require children objects
Each children should have a unique sequential ID as primary key and a unique sequential ID based on the relation, like bellow:
Object id: 1
Children id: 1, internal_id: 1
Children id: 2, internal_id: 2
Object id: 2
Children id: 3, internal_id: 1
Children id: 6, internal_id: 2
Children id: 7, internal_id: 3
Object id: 3
Children id: 4, internal_id: 1
Children id: 5, internal_id: 2
Children id: 8, internal_id: 3
Children id: 9, internal_id: 4
Currently I'm using a before_save filter to pin the internal_id but I feel this is a bad practice and could be improved with some sql magic
def define_internal_id
self.internal_id = 1 + Children.unscoped.where(parent_id: self.parent_id).count
end
before_save :define_internal_id
Is there a better way to solve this?
This is exactly what the acts_as_list gem is for. First, add it to your Gemfile:
gem 'acts_as_list'
Then in your model, add:
acts_as_list column: :internal_id, scope: :parent_id
This will number internal_id starting at 1, scoped to the parent_id column, as in your examples. If you want to start at 0 set the option top_of_list: 0.
See the acts_as_list repo for other options.
I have
#total = Purchase::Total.find(1);
Total model have:
has_many :items
belongs_to :member
belongs_to :company
..................
Also companies model has
has_many :addresses
has_one :subscription
..................
and a lot more
How can I get a tree from the #total object containing all the has_one, belongs_to dependencies?
I.E.
<Purchase::Total id: 3, member_id: 4, created_at: \"2015-11-25 14:47:46\", updated_at: \"2015-11-25 14:47:46\", affiliate_company_id: nil, is_paid: false, currency: 1, company_id: 37020, ser_id: 2>
<Company id: 37020, name: \"Andrew\", parent_id: 37019, member_company_id: 37019, payment_company_id: 37019, widget_id: 3003359>
And so ..... (I did the example with: #total.inspect and #total.company.inspect), and I need something like inspect to return automatically all the objects.
Using reflect_on_all_associations
Take a Queue and a Hash and add Total (model name) to it.
Pop a model name, get all associated models and add them queue. Also, using the tablize name of current model, create a new entry in hash and add the tablized names of associated models.
If queue is not empty, go to 2.
At the end, your hash should look like:
{ total: { company: [ :subscription, :addresses ] }, items: { associated: { another: :another_one } } }
Then you can use this in your query:
Total.where().join(hash[:total])
It will fetch all the associated data as well. Then you can simply loop through the attributes. If attribute type is ActiveRecord (or similar), then its an associated model data.
This model:
class SimCustomer < Customer
index({ user_id: 1 }, { background: true })
belongs_to :user, :inverse_of => :sim_customers
end
inherits from this model:
class Customer
include Mongoid::Document
include Mongoid::Timestamps
field :mail_address, type: String
end
I create the indexes from my terminal:
bundle exec rake db:mongoid:create_indexes
But this creates indexes on the Customer instead of the SimCustomer:
I, [2014-11-13T16:21:17.210343 #11407] INFO -- : MONGOID: Created indexes on Customer:
I, [2014-11-13T16:21:17.210381 #11407] INFO -- : MONGOID: Index: {:user_id=>1}, Options: {:background=>true}
And when I try to batch insert SimCustomer objects it creates Customer objects instead:
SimCustomer.collection.insert(Array.new << {mail_address: "hello#hello.com", user_id: "54652f5b43687229b4060000"})
# => #<Customer _id: 54654b7b6220ff4f28364ee9, created_at: nil, updated_at: nil, mail_address: "hello#hello.com", _type: "Customer">
How can I fix this?
This sets up Single Collection Inheritance:
class SimCustomer < Customer
That means that both Customer and SimCustomer will be stored in the customers collection inside MongoDB and they'll be differentiated using the _type field.
Specifying an index in SimCustomer:
class SimCustomer < Customer
index({ user_id: 1 }, { background: true })
will create the index on the customers collection because that's where SimCustomers are stored.
The same collection chicanery is causing your problem with your bulk insert. If you look at SimCustomer.collection.name you'll find that it says 'customers' so of course SimCustomer.collection.insert will create new Customers. If you want to create SimCustomers by hand then specify the _type:
SimCustomer.collection.insert(
_type: 'SimCustomer',
mail_address: "hello#hello.com",
user_id: "54652f5b43687229b4060000"
)
Note that I dropped that strange looking Array.new << stuff, I don't know where you learned that from but it is unnecessary when inserting on object and odd looking if you were inserting several, if you want to insert several then just use an array literal:
SimCustomer.collection.insert([
{ ... },
{ ... },
...
])
Your next problem is going to be that string in user_id. That really should be a Moped::BSON::ObjectId or you'll end up with a string inside the database and that will make a mess of your queries. Mongoid may know what type a property should be but neither Moped nor MongoDB will. You'll want to use Moped::BSON::ObjectId('54652f5b43687229b4060000') instead.
I have the following model structure in my Rails 4.1 application:
delivery_service.rb
class DeliveryService < ActiveRecord::Base
attr_accessible :name, :description, :courier_name, :active, :country_ids
has_many :prices, class_name: 'DeliveryServicePrice', dependent: :delete_all
end
delivery_service_price.rb
class DeliveryServicePrice < ActiveRecord::Base
attr_accessible :code, :price, :description, :min_weight, :max_weight, :min_length, :max_length,
:min_thickness, :max_thickness, :active, :delivery_service_id
belongs_to :delivery_service
end
As you can see, a delivery service has many delivery service prices. I'm trying to retrieve records from the delivery service price table; selecting the record with the lowest price attribute within the unique scope of the foreign key, delivery_service_id (so essentially the cheapest delivery service price per delivery service).
How can I select unique records from a table, with the foreign key attribute as the scope?
I hope I've explained this enough, let me know if you need anymore information.
Thanks
UPDATE #1:
Example of what I'm trying to achieve:
delivery_service_prices table:
id: 1, price: 2.20, delivery_service_id: 1
id: 2, price: 10.58, delivery_service_id: 1
id: 3, price: 4.88, delivery_service_id: 2
id: 4, price: 1.20, delivery_service_id: 2
id: 5, price: 14.99, delivery_service_id: 3
expected results:
id: 1, price: 2.20, delivery_service_id: 1
id: 4, price: 1.20, delivery_service_id: 2
id: 5, price: 14.99, delivery_service_id: 3
Due to PostgreSQL being more strict with abiding the SQL standard (rightly so), it requires a bit of tweaking to get the correct results.
The following query returns the correct results for the lowest delivery service price, per delivery service:
DeliveryServicePrice.select('DISTINCT ON (delivery_service_id) *').order('delivery_service_id, price ASC')
I need to add the delivery_service_id attribute to the order condition, or PostgreSQL throws the following column error:
PG::InvalidColumnReference: ERROR: SELECT DISTINCT ON expressions must match initial ORDER BY expressions
Hope this helps anyone who stumbles upon it!
To get the minimum for a single record you can use
DeliveryServicePrice.where(delivery_service_id: x).order(:price).limit(1).first
or if you have a delivery_service object available
delivery_service.prices.order(:price).limit(1).first
UPDATE
If you want all minimums for all service_delivery_ids you can use a group query
DeliveryServicePrice.group(:delivery_service_id).minimum(:price)
which will get you almost where you want to go
{
1: 2.20,
2: 1.20,
3: 14.99
}
with a hash containing the delivery_service_id and the price. (you can't see the price_id )