Combining data from two tables in rails - mysql

I have two models, one belongs to the other. They look like this:
class LittleClass < ActiveRecord::Base
has_many :little_class_sessions
end
and
class LittleClassSession < ActiveRecord::Base
belongs_to :little_class
end
LittleClassSession has a column called little_class_id. I want to get all LittleClassSession but also have the associated LittleClass returned to me in the same hash.
Is there some way to do this that's built into Rails? Or is there a clean way to do this?
And is this something that I build into the LittleClass or LittleClassSession model with scope?

When you query ActiveRecord you will get an array of ActiveRecord:Relation. It is a specific entity which starts your query. You can of course join dependent tables (as in your example with one-to-many relation). But you will still need to go over those dependent relations to build whatever object you need.
Here is a sketch of what I mean (assume we search for all little class sessions with specific little class id):
class_sessions = LittleClassSession.includes(:little_class).where(:little_classes => {:id => 1})
class_sessions.each do |relation|
test_hash = relation.attributes.merge!({:little_class => relation.little_class.attributes});
puts test_hash
end
test_hash will include all the attributes of the little class session as well as attributes of the little class under corresponding key.

Related

rails includes query loading entire data for included models

I have a rails application where I have following models.
BookingHotel
has_many :hotel_picture_partners, through: :hotel_pictures
has_many :booking_hotel_partner_details, dependent: :destroy
BookingHotelPartnerDetail
belongs_to :booking_hotel
HotelPicturePartner
belongs_to :hotel_picture, dependent: :destroy
I have a query as follows
#booking_hotel_partner_details = BookingHotelPartnerDetail.unscoped.select(:id, :booking_hotel_id, :partner_booking_hotel_id).includes(booking_hotel: :hotel_picture_partners)
This puts memory under pressure as it loads all data for included models.
Is there a way I can only load selective fields from booking_hotels & hotel_picture_partners tables ?
Also I want to get an activerecord array as response.
pluck method loads only attributes, without loading whole models. check it: http://apidock.com/rails/ActiveRecord/Calculations/pluck.
Try to rewrite it like this:
BookingHotelPartnerDetail.unscoped.select('booking_hotels.id as bh_id', 'hotel_picture_partners.id as hpp_id').joins(booking_hotel: :hotel_picture_partners)
Your project is probably already pretty far along, but for anyone else wanting this behaviour I've released a patch that filters columns if you have a .select(...) along with .includes(...) or .eager_load(...).
It's now included in a data-related gem I maintain, The Brick.
It works by overriding ActiveRecord::Associations::JoinDependency.apply_column_aliases() like this.
In order to enable this selective behaviour, add the special column name :_brick_eager_load as the first entry in your .select(...), which turns on the filtering of columns while the aliases are being built out. Here's an example based on your code:
#booking_hotel_partner_details =
BookingHotelPartnerDetail.unscoped
.includes(booking_hotel: :hotel_picture_partners)
.select(:_brick_eager_load, :id, :partner_booking_hotel_id, 'booking_hotel.name', 'hotel_picture_partners.notes')
Feel free to add myraid additional columns from any table as strings in the same way as the last two sample items I put into the .select(...).
Because foreign keys are essential to have everything be properly associated, they are automatically added, so you do not need to include :booking_hotel_id in your select list.
Hope it can save you both query time and some RAM!

Using form to update has_many through join table

I am short of implementation ideas for my rails project. at this point it seems impossible to implement in rails.
I am cloning a sort of accounting software into a web app using rails framework for small manufacturing companies to keep track of their products stock in their different distribution branches.
I have 3 different models: "Product", "Branch" & "Accumulator"
class Branch < ActiveRecord::Base
has_many :accumulators
has_many :products, :through => :accumulators
end
class Product < ActiveRecord::Base
has_many :accumulators
has_many :branches, :through => :accumulators
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
end
end
class Accumulator < ActiveRecord::Base
belongs_to :product
belongs_to :branch
end
I am new to rails and after reading up on many to many associations I came across using collections to add products to a branch "#branch.products << Product.all"
Is there a possible way to use a form "number_field_tag" in the branch show view to add multiple of specific products into the join table?
eg
I want to add 10 of (Product) called "garden eggs" to a (Branch) called "lagos branch" to the (Accumulator) join table using a form in Branches show view?
Congratulations for choosing :has_many, through: you will not regret it.
Is the relationship between a product and a branch static?
Or does it change a lot?
In your Accumulator model, add an integer field called amount (count can have conflicts). Then you either create a form for your Accumulators or you add a nested form with for example Cocoon.
This way you can add Accumulators to your Branch with a certain Product and a certain amount.
Off topic:
Here is an article about why has_many through has some advantages:
http://blog.flatironschool.com/why-you-dont-need-has-and-belongs-to-many/
If you have problems with forms I can really recommend SimpleForm and for nice Javascript-assisted fields I recommend Select2.
If the table accumulators needs to save only two things: product_id, and branch_id, you can easily use has_and_belongs_to_many associations.
class Branch < ActiveRecord::Base
has_and_belongs_to_many :products, join_table: 'accumulators'
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :branches, join_table: 'accumulators'
end
And now, there is no need for the third model.
As far as it goes, how to add a relationship, it's pretty easy in this case:
branch = Branch.last
branch.products << Product.create # you don't need to touch the middle table.
Instead of using number_field_tag to ask for plain ids, you can use something fancy like jQuery Chosen Plugin. This plugin will allow you to use tag like input, and will send the ids to the server separated by ,'s.

Rails query on different models in a multi-level association chain

I have a multi-level model structure, and I am trying to create a query where I can search for either an attribute on the main parent model, or the last model in the associatioon change. My structure looks like the following:
class Parent
attr_accessible :pname
has_one :child
end
class Child
has_many :infos
end
class Info
has_one :setting
end
class Setting
has_many :subsettings
end
class Subsetting
attr_accessible :sname
end
What I am trying to do is create a where query, where i can pull all parents where either the "pname = X" or "sname = X". However, I am unsure of how to create the associations that deep: Is there a way I can do it cleanly using active record, or is it better to create a mysql query directly?
I'm typing this freehand, so it's possible this won't be 100%, but you should be able to do something like the following...
class Parent
has_one :child
has_many :infos, through: :child
has_many :settings, through: infos
has_many :subsettings, through: :settings
...
end
Then you should be able to call...
Parent.joins(:subsettings).where("parent.pname = ? OR subsetting.sname =?", x)
Two things to note about the .where() call:
Because you are querying against multiple joined tables, you need to preface the column with the table name.
The table name is singular, not plural. That's why subsetting and not subsettings.

Save model id as foreign key through has_one / belongs_to

I'll briefly explain my situation: I have a model called "tax" which belongs_to a "user" and of which a "user" has_one.
In my users table I have a column called "tax_id" which I want to store the id of the tax model when a user creates one.
Currently, in my tax model the create function looks something like this:
class Tax < ActiveRecord:Base
belongs_to :user
tax = Tax.new(income: income, taxes: taxes, rrsp: rrsp)
tax.save
and then in the taxes_controller file, the create function looks like this:
def create
#tax = Tax.new(secure_params)
#tax.user = User.find(current_user.id)
if #tax.save
redirect_to show_tax_path(current_user.tax)
else
render :new
end
end
(secure_params) being the strong parameters for the field inputs set in a private definition.
Now, someone mentioned that I may have better luck if I use build but unfortunately I couldn't get it to work at all, something to do with how I'm using current_user (devise). Currently, my setup works just fine, other than saving the tax model id in the user model column "tax_id" like I said.
I'm wondering if I perhaps need to add a foreign ID key to either the belongs_to or has_one statement, even though I was under the impression that the "link" should be made automatically as long as the column was named "[model]_id"
try using
user.build_tax
I think this might help you out.
The build syntax for has_many association:
user.taxes.build
The build syntax for has_one association:
user.build_tax # this will work
user.tax.build # this will throw error

Rails merging tables

I have two tables: Members and Addresses. How can I merge these two tables together in my model, so that I could combine all their columns together? For example, Members has a column named position and Addresses has a column named street. How could I make it so that I could have Position and Address in the same virtual table. Is there a merge function for this?
Not sure why you need to create a separate model, you can use the basic Ruby constructs for this:
I'll assume Member has a column called address_id, that is a member belongs_to an Address. This will automatically associate the joins for you.
So all you need to do is something like this:
class Address < ActiveRecord::Base
end
class Member < ActiveRecord::Base
belongs_to :address
end
member = Member.create(:address => Address.find(123))
If you want to get the address and just the position field then go:
member = Member.find(456)
position = member.address.position
or perhaps:
Member.joins(:address).select("members.position, addresses.street")
Not sure what you are trying to do, but if it is something very specific, you could also try creating a View in your database and then making a model for it, treating it like a regular table.