Ruby on Rails: Use existing Model if possible - ruby-on-rails

I want to create a relationship from recipe to ingredients. Basically:
recipe has_many ingredients
ingredients belongs_to recipe
But if I add a ingredient to a recipe it should look if there is an existing ingredient with the same name and should use that one.
Is there a smooth solution?

You need to expand your schema out: you need to differentiate between an ingredient like "all purpose flour", of which you want one in your database, and then "100 grams of all purpose flour" which might be used in a specific recipe.
I would do something like this:
Recipe
has_many :recipe_ingredients
#fields - name
RecipeIngredient
belongs_to :ingredient
belongs_to :recipe
#fields - quantity
Ingredient
has_many :recipe_ingredients
#fields - name
Now, when you build a recipe, you're building a list of associated recipe_ingredients, each of which points to an ingredient (like the "all-purpose flour" ingredient) and has a quantity, eg "100 grams".
Note - i could have added "has_many :ingredients, :through => :recipe_ingredients" to Recipe, but i don't actually think this is a useful association: ingredients only make sense for the recipe when they have a quantity - i don't think you would ever want to say "recipe.ingredients" as this doesn't give you the quantity info.

Having all realations set up in a standart way (HABTM) you could add ingrediants by name like this:
# reciept.rb
def add_ingredient_by_name(ingredient_name)
self.ingredients << Ingredient.find_or_create_by(name: ingredient_name)
end
Update:
Also I'd add a uniqueness constraint for ingredient name for safety:
# ingredient.rb
validates_uniqueness_of :name

Related

Rails 5 use belongs_to with condition for different tables

I am working on a rails app, with different tables and associations, and trying to find out the best solution for that, don't know yet.
One table/class is called categories
For example
Categories
- Stocks
- Reits
-(...)
One table for each category
Stocks
belongs_to :category
Reits
belongs_to :category
Than i want to create a table called "Dividends", with a condition, don't know if is possible, for example:
Dividends
belongs_to :category
if category_id == 1
belongs_to :stock
end
if category_id == 2
belongs_to :reit
end
With the command:
rails g scaffold dividends category:references stock:references reit:references
But i don't know if it would be confusing, an if maybe would be better create a table for each class, for example:
StocksDividends
belongs_to :category
belongs_to :stock
ReitsDividends
belongs_to :category
belongs_to :reit
Would like some help on thinking about that solution.
just a quick hint - take a look at polymorphic associations:
https://guides.rubyonrails.org/association_basics.html#polymorphic-associations
The mechanics of it put a foreign key in the dividends table along with a type column. The type column tells you what type of record is the parent - the stock or the reit.

How to use joins and where in ruby on rails?

Im having troubles with using .joins and .where
In my app the users can search for recipes using their ingredients as parameters.
For example, if you have rice and tomatoes, it will show you all recipes with rice and tomatoes (but if the recipe use a third ingredient it is not displayed).
Anyway, I have recipe and ingredient model and recipe model and a model for the join table called has_ingredient.
The model is basically something like this:
recipe --< has_ingredient >-- ingredient
Everything is working when I create recipes, it actually store the id of recipes and id of ingredients in the has_ingredient table.
anyway, for searching I created a separated model for it, I can actually select ingredients and send them to the controller via get method, but I having problems with this
#result=Recipe.joins(:has_ingredient).where(has_ingredient: {ing_id: params[:ingredients]})
I want to store in #result the list of recipes, but when I try to search i get the following error
Association named 'has_ingredient' was not found on Recipe; perhaps you misspelled it?
Im not sure what is the problem and Im having a hard time with RoR
I think you should set it up like this:
class Recipe < ActiveRecord::Base
has_many :recipe_ingredients
has_many :ingredients, through: :recipe_ingredients
end
class Ingredient < ActiveRecord::Base
has_many :recipe_ingredients
has_many :recipes, through: :recipe_ingredients
end
Then RecipeIngredient would be the join model.
class RecipeIngredient < ActiveRecord::Base
belongs_to :recipe
belongs_to :ingredient
end
You can read this great basics guide for more information on how to set everything up:
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
If you set it up like this you can then use joins in the query like this:
#result = Recipe.joins(:ingredients).where(ingredients: { id: params[:ingredients] })
In the joins part of the query you have to use the association name and in the where clause you have to use the actual table name. (in this case it is both ingredients).
Using the association and table name might fix the problem for your current setup, even though I advise not to use the name has_ingredient for the model.

Has many conditions in Rails 4

How to do this:
has_many :space_mappings, -> { where(group_id: group_id) }, through: :category
That is - SpaceMapping and this model both has a group_id and they have to match. I could just make a method but I would like for this to be possible.
Here I get:
undefined local variable or method `group_id' for #<ActiveRecord::Relation::ActiveRecord_Relation_SpaceMapping:0x007fe5ac118bd8>
I have done this instead:
def space_mappings
category.space_mappings.where(space_id: Space.where(group_id: group_id))
end
Thanks in advance.
You must assign a value for category_id.
See http://guides.rubyonrails.org/association_basics.html (4.3.3.1 section).
It can help your for understanding details and clear concept.
If "this model" has a belongs_to :category relationship or a has_one :category relationship, then you shouldn't need that where clause at all. The whole point of "has many through" is to restrict the associated models to those that are associated with the model they're associated through
That is, you should just be able to do
belongs_to :category
has_many :space_mappings, through: :category
assuming that space mappings also belong to a category.

How to create correct database scheme of cooking site?

I want to make a cooking site but don't know the correct was to build database.
My models are: Recipe and Ingredient.
Ingredient in recipe should be autocomplete field. The problem is that user can put there any text. ("cucumber" or "cucamber") and it will be different ingredients.
I want to make a search by ingredients and links to them. What is the best way to do it?
A recipe has many items, which in turn keeps a reference to an ingredient, an amount and a measure type. So you can go with:
rails generate model Recipe name:string description:text
rails generate model Item recipe:references ingredient:references amount:decimal measure:string
rails generate model Ingredient name:string
and then add to your classes:
class Recipe < ActiveRecord::Base
has_many :items
has_many :ingredients, :through => :items
# this allows things like #recipes = Recipe.using("cucumber")
scope :using, lambda do |text|
joins(:ingredients).where("ingredients.name LIKE ?", "%#{text}%")
end
end
class Item < ActiveRecord::Base
belongs_to :recipe
belongs_to :ingredient
VALID_MEASURES = %w[oz kg tbsp] # use for "select" tags in forms
validates :measure, :inclusion => VALID_MEASURES
end
class Ingredient < ActiveRecord::Base
belongs_to :item
end
From here you start building your views, autocomplete, whatever your imagination allows.

Rails polymorphic association with connection table

I have a table called recipes and another called ingredients. Ingredients can either connect to foods or recipes (one recipe can contain other recipes). I have implemented it with the food part of it but I'm not sure how to implement the recipe part of it. I created another table called the food part of it called recipe_as_ingredients which I will neet to populate when a recipe is saved with the recipes selected as ingredients in the current recipe. I would probably have to update the table before each save and manually delete lines if deleted for the recipes. Is there a better way of implemnting it?
Here are the models:
class Recipe < ActiveRecord::Base
has_many :ingredients
end
class Ingredient < ActiveRecord::Base
belongs_to :element, :polymorphic => true
belongs_to :recipe
end
class Food < ActiveRecord::Base
has_many :ingredients, :as => :element
end
class RecipeAsIngredient < ActiveRecord::Base
has_many :ingredients, :as => :element
end
I manually set the element type in a function before saving so I would need to to similar for a recipe as ingredient but make sure that recipe_as_ingredient contains a record to connect to the ingredient:
self.element_id = numid.id
self.element_type = 'Food'
p.s. I could not connect the recipe without the recipe_as_ingredients connection tables because it made saving the record impossible because recipe was both a master record and detail record and the id field was always nil.
You're so close.
Move:
has_many :ingredients, :as => :element
Onto the Recipe model.
RecipeAsIngrident should exist. If you want to get all the Foods used in the recipe then you want a function on Recipe to sum up the descendants. This would be a calculated total, so you wouldn't need callbacks for updating totals etc, however I would add logic to prevent a recipe being deleted which is used for something else.
Ask if you need more clarification.

Resources