I have a model like this:
Recipe:
has many ingredients
Ingredient:
has many recipes
IngredientList:
Join table for both model classes plus some additional classes
What is the best practice for adding a IngredientList with a reference to ingredient and recipe?
Should I make a mutation like this:
addRecipeIngredient(recipe {name: 'Wiener Schnitzel'}, ingredient {name: 'Schnitzel'})
or
addIngredientList(recipe: 1, ingredient: 1)
With the second approach the recipe and ingredient would have to be created beforehand
Related
I'm new to Rails and I'm not sure how to do this:
I'm writing a rake script that needs to reference off of a value from two tables:
The owner_id in the Animals table references the Owner table:
Animals:[
{id:1, name:"Bow wow", owner_id:1, score:null},
{id:2, name:"Chiaow", owner_id:2, score:null},
{id:3, name:"Fishbob and Ben", owner_id:9, score:null}
]
Owner:[
{id:1, name:"Doug"},
{id:2, name:"Michelle"},
{id:9, name:"Ben"}
]
I would like to combine both these tables to get a result that looks like this:
Combined = [
{id:1, score:null, keywords:"Bow Wow Doug", name:"Bow wow", owner:"Doug"},
{id:2, score:null, keywords:"Chiaow Michelle", name:"Chiaow, owner:Michelle",
{id:3, score:null, keywords:"Fishbob and Ben", name:"Fishbob", owner:"Ben"}
]
I want to also index through the keywords using
combined_list = Combined.where("keywords LIKE (?)", "%#{chosen_word}%")
Is this possible?
If you join two models (Animal and Owner) you can select which attributes from the joined table you want to make available in the instances:
combined = Animal.joins(:owner).select(:id, :name, 'owners.name as owner_name')
puts combined.first.name, combined.first.owner_name
This implies of course, that the Animal model belongs_to :owner.
To filter this relation I would do this:
cw = "%#{chosen_word}%"
combined.where('animals.name LIKE ?', cw).
or(combined.where('owners.name LIKE ?', cw))
I'm in the middle of developing a bike website when I stumbled on question.
I have the follow models (to simplify my description I left some models and attributes aside):
model_name:some attributes (example)
bike: name, price, color (Giant Anthem, 3999, black)
category: name (Brakes or Shifts or Transmissions, etc)
component: name (Shimano SLX or Shimano XT or Shimano XTR - in this case for components for the transmission category)
So the relationship of these models are the followed:
A bike has many components
A component is on many bikes
A component belongs to a category
A category has many components
Right now I've created these 3 tables and made the association: category has_many components and component belong_to category. Everything works well. Now I have to create a jointable and use the has many through association between bike and component BUT the problem for me is to understand the next step after that because I don't want only one dropdown to select all components. I want to select the components divided by category. Something like this:
How can I achieve this? Hope you can help me. Thank you!
The tricky part is that you want to split the select of the same association on different fields. You may need to handle the name of the field manually, something like this:
= select_tag 'bike[component_ids][]', options_from_collection_for_select(frames_category.components.all, :id, :name)
= select_tag 'bike[component_ids][]', options_from_collection_for_select(breakes_category.components.all, :id, :name)
= select_tag 'bike[component_ids][]', options_from_collection_for_select(transmissions_category.components.all, :id, :name)
= select_tag 'bike[component_ids][]', options_from_collection_for_select(tyres_category.components.all, :id, :name)
Note the names of the attribute `bike[components_ids][]'. The params hash on your controller will look something like:
params == {bike: {name: 'some name', price: '200', component_ids: [1,3,6,8]}
ActiveRecord should handle the assignment of the components using the collection_singular_ids= https://guides.rubyonrails.org/association_basics.html#methods-added-by-has-many-collection-singular-ids-ids
I'm not 100% sure it works on has many through but personally I wouldn't use a has many through there, "has and belong to many" seems to just fit your needs and it requires less configuration.
I have to activerecord models
Model1 and Model2
Model1 has name and info fields
Model2 has state and price
I want to make an array of objects which will be a union of model1 + model2.
Each sum_model object should have name, info, state, price properties.
It should be the sum of Model1.all and Model2.all. For example:
If Model1.all returns one record with name="name" and info ="zz"
Model2.all returns one record with state='state' and price=14
model_sum should be an array of 2 objects:
[{name:'name', info: 'zz', state: '', price: ''}, {name:'', info: '', state: 'state', price: 14}]
How do I do this?
You should be able to do what you want to achieve by building the cartesian product (combine every record of one table with every table of another table) between Model1 and Model2 and then get the attributes of the resulting model (which will have the attributes of Model1 and Model2 combined:
Model1
.joins("CROSS JOIN #{Model2.table_name}")
.select("#{Model1.table_name}.*, #{Model2.table_name}.*")
.map(&:attributes)
No association needs to exist between the two models in order to do that.
Edit after rereading the question and noticing that I missed the point
You will first have to adjust the selects of both models in order to get the UNION to match columns. Luckily, one can add arbitrary selects into the AR statement, so e.g.
m1 = Model1.select(:name, :info, "'' as state", "'' as price")
m2 = Model2.select(:state, :price, "'' as name", "'' as info")
Then you will have to handcraft the UNION as this is not supported by AR. It is by Arel but I most of the time doubt that Arel is worth the struggle:
union = Model1.connection.unprepared_statement do
"((#{m1.to_sql}) UNION (#{m2.to_sql})) AS unioned"
end
And after that you can fire away the select using the union as the from value and then call the attributes method of each returned entry to achieve the result you specified:
Model1
.select('*')
.from(union)
.map(&:attributes)
May I know how to create one to many relationship into Google Cloud Datastore in Ruby and Ruby on Rails?
Now I'm writing a code like this.
class Author
attr_accessor :name, :books
end
class Book
attr_accessor :title, :description, :author_id
end
> #author.books
[2, 3, 5]
> Book.find(#author.books.first)
<Book: ....
I'm putting some Book ids into Author's books.
But I feel there is more sophisticated way.
I'd like to implement the code using 'belongs_to' and 'has_many' into Google Cloud Datastore. Is it possible?
You can declare book as a child of an author:
book_key = datastore.key [["Author", "Someone"], ["Book", "sampleBook"]]
See more at Entities, Properties, and Keys >> Ancestor Paths documentation.
Think VERY CAREFULLY before using this structure. If a book happens to have multiple authors, you'll need to replicate books many times for each author. In Datastore, each child can have only one parent. There's not an official many-to-many relationship in Datastore, although you can mimic it in your code and data structure, similarly to how you're already doing (with a custom authorid property in Book entity).
I concur with Renato. You essentially have a many-to-many scenario. An Author can write several Books and conversely Books can have multiple Authors.
Unfortunately there is no explicit mechanism for many-to-many relationships in Google Datastore. But you can still structure your entities to model the relationship.
For example, instead of using a hierarchical model via ancestor paths, add an array to your Book entity that store keys that reference Author entities which might look something like this:
book_key = datastore.key "Book"
author_key1 = datastore.key "Author", "john"
author_key2 = datastore.key "Author", "jane"
author_entity1 = datastore.entity author_key1 do |t|
t["name"] = "Doe, John"
end
author_entity2 = datastore.entity author_key2 do |t|
t["name"] = "Doe, Jane"
end
datastore.save(author_entity1, author_entity2)
And the array property on the Book entity would look something like this:
book_entity = datastore.entity book_key do |t|
t["authors"] = [author_key1, author_key2]
end
If you want to know all the books associated with author John Doe in your database all you need do is query the "authors" array property:
query = Google::Cloud::Datastore::Query.new
query.kind("Book").
where("authors", "=", datastore.key("Author","john"))
books_by_john = datastore.run query
Notice that I could have also gone the other way and created an array of Book keys on Author entities. But had I gone that route and tried to model a prolific Author like say Stephen King...well that Author entity would end up being pretty bloated with key references to Book entities, so you have to be selective as to which side of the relationship you add the array and try to go for the entities less likely to have bloat.
I have this code:
Business.all.limit(50).each do |business|
card = {name: business.name, logo: business.logo, category: business.category.name}
feed << card
end
In my models, Business belongs to Category, and Category has many Business
My problem is that this will query the DB 50 times, each time I want to retrieve each business' category name.
I have seen Rails cache effectively by using :include, but all examples I have seen are for child records, for example:
Category.all :include => [:businesses]
but in this case I want to cache the parent's data.
Its the same you can do by using singular model name
Business.includes(:category)