Rails merging tables - mysql

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.

Related

Best performance wise query to get parent of queried nested resource

I am implementing an availability model nested within a listing. Its for a rental app.
class Listing
has_many :availabilities, dependent: :destroy
end
class Availability
belongs_to :listing
end
availabilities table has start and end date columns.
I am writing a query through search form to find listings where availabilities are present and the date given in the form lies in between start and end dates fo those availabilities.
My query in a class method looks like:
def self.search(params)
date = params[:date]
listingsids = Availability.where('startdate <= ?', date).where('enddate >= ?', date).pluck('listing_id')
products = Listing.where(id: listingsids)
end
However i feel this is not efficient. I wish I can write Listing.joins(:availability) and then use it but rails won't allow it. I can only join the other way which will give me a relation with availability objects and I want listings i.e. parent resource.
How can I make it more efficient and reduce number of queries I am doing?
Will appreciate your help :)
You should be able to use joins on listing to get you availablity relations, joins works using the relation name, not the model name, so instead of joins(:availability) you should be using joins(:availabilities). Something like this should work and use just a single query for your case:
Listing.joins(:availablities).where('availability.startdate <= ?', date).where('availability.enddate >= ?', date)
notice that joins uses the relation name joins(:availabilities) but the string in the where uses the table name where('availability.startdate <=?', date)

Combining data from two tables in rails

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.

Sorting associated objects based on the association's creation date

Right now, I'm working on a simple app. It requires to get the associated objects ordered by the date that they we're added to the object. For that, I want to order them based on the pivot-table's id.
My app looks a bit like this:
class Product < ActiveRecord::Base
has_and_belongs_to_many :users
end
class User < ActiveRecord::Base
has_and_belongs_to_many :products
end
However, when a user wants to buy a product, I would add a new relation into the pivot table courses_users. When I then run #product.users, I will get them back in the order the users where created, not added as the relation.
I've tried creating a query scope, but it didn't work. I also tried to create a order on the has_and_belongs_to_many, as such:
has_and_belongs_to_many :users, order: 'course_users.id ASC'
But none of that seemed to work, no ORDER statement could be found in the logs.
Add the created_at field to your table.
rails g migration AddTimestampsToCourseUsers created_at:datetime
then you can
#product.users.order "course_users.created_at ASC"

What is the best way to merge 2 tables with Active Record and Mysql

We need to allow users to customize their entities like products... so my intention was to have a product table and a custom_product table with just the information the users are allowed to change.
When a client goes to the product I want to merge the information, means I want to merge the two tables - the custom overwrites the default Products table.
I know that in mysql there exists a ifnull(a.title, b.title) way but I was wondering if there is any nice and efficient way to solve this in Rails 4 with Active Record. Assume that the products and custom products table have just 2 columns, ID and TITLE
I think you can convert both objects to JSON and then handle their params as a hash, using the merge method:
class Product
end
class Customization
belongs_to :product
end
a = Product.find(...)
b = a.customization
c = JSON(a.to_json).merge(JSON(b.to_json).reject!{|k,v| v.nil?})
Therefore c will contain all params from Product eventually overridden by those in Customization which are not nil.
If you still want to use a Product object with hybrid values (taken from Customization) you can try this:
a.attributes = a.attributes.merge(b.attributes.reject!{|k,v| v.nil?})
In this case a will still be a Product instance. I would recommend to keep the same attributes in both models when doing this.

Rails MySQL auto generated column

I am working on RoR 3.x with MySQL as backend.
Is there any way to modify the existing id (autogenerated with migration) in a way that can generate particular user defined pattern.
For e.g : "Products Table" should have values in "id" field like "P01", "P02" and so on, where P can be specified by the user, and 01,02 are autogenerated.
Thanks in advance!
The 'regular' IDs (1, 2, 3, ..., n) in this case aren't generated by rails but by MySQL (using AUTO_INCREMENT). So, if you want to go with auto-generated, auto-incrementing IDs, I would suggest not messing with this. What you could do, and what I would suggest, is creating an additional column and then populating that using a callback on your model.
Example:
class Product < ActiveRecord::Base
attr_accessor :user_supplied_prefix
after_create :generate_user_supplied_id
private
def generate_user_supplied_id
update_attribute(:user_supplied_id, "#{self.user_supplied_prefix}#{self.id}")
end
end
The downside of this approach is that Product.find(user_supplied_id) won't work. Fortunately, Product.find_by_user_supplied_id(user_supplied_id) will.