This is my first question, ive looking for an question similar but hadnt found it, i'm starting learning ruby on rails and i followed a course that said for creating foreing keys with has_many
i create my class Band by.
rails g model Band name:string website:string email:string
and i also have created my class Genres in the same way
this orders generate classes like
class Band < ActiveRecord:Base
end
so i edit my file Band.rb like this
class Band < ActiveRecord:Base
has_many :Genres
end
save changes (Ctrl+S) and when i try to create a new object o class Band
a = Band.new
a hasnt the genres atribut
Edit your band.rb file to:
class Band < ActiveRecord:Base
has_many :genres
end
reload, and everything should be fine since then.
First make sure that in Your Genre model you have
belongs_to :band
Also in you Band model lowercase you has_many relationship like so
has_many :genres
since a genre belongs to a band you need to have a band_id in you genres table which will point to the band that genre belongs to.
then you can easily find the band the genres for a band.In you controller you can find a band
#band = Band.find(params[:id])
and to check the genre that was set before you can do
#genre = #band.genres
this will give you the correct genres for that band .
However this seems more like a situation where a band has_many :genres and a genre has_many :bands.In this case you may want to use a has_and_belongs_to_many relationship.You can find more details for associations in the rails guides here: http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
If you go with the has_and_belongs_to_many relationships you need to create a separate table where each genre and band will point to each other so you can associate them easily
the new method will not create the actual record in the database, you have to call save on the instance. To create associate genre, you can call create_genre on the already exists Band instance.
Related
I have two models, Student and Absence, with the relationship:
class Student < ActiveRecord::Base
has_many :absences
class Absence < ActiveRecord::Base
belongs_to :student
I want to see how many absences have been logged for each student, and show that total on the student's #show page. In the console, I'm able to query this by calling:
a = Student.find(1)
a.absences.size
However, I can't seem to get it to work in the app itself. Would the preferred way of querying this in the app be in the model or the controller?
This will never work, since you are calling association on the model, not instance. At first you should fetch a student and then count associated records:
Student.find(<id here>).absences.size
To aggregate this information for all students, you can add absence_count attribute accessor in Student model:
attr_accessor :absence_count
and then do something like this:
Student.includes(:absences).each{|s| s.absence_count = s.absences.size}
If you just need to output it in the view, then you can try the following:
Student.includes(:absences).each do |student|
puts student.absences.size
end
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.
I need to solve two tasks in my rails app and i need some advice:
I have Person model and Car Model. One person can have only one car. it means that Car always has driver = person, but not each person has a car. So i need uni-directional One to One here. Is it possible to implement with rails? Actually i need has_one on Car and i don't need belongs_to on Person
I have Order and Load models. In my system there are many orders and when i am ready to deliver these orders I construct new Load object and put all orders which i want to deliver there. So every Load has_many orders but not each order belongs_to Load. It is uni-directional one-to-many... Also i don't need something like order.load, i need only load.orders
So how can I implement it with rails?
class Person < ActiveRecord::Base
has_one :car
end
class Load < ActiveRecord::Base
has_many :orders
end
Then you can call person_instance.car or load_instance.orders. You will have to have load_id on the orders and person_id on the cars
For example we have:
class PublicLibrary < ActiveRecord::Base
has_many :books
end
class Book < ActiveRecord::Base
belongs_to :public_library
end
If we want do update all books in PublicLibrary, we can add to PublicLibrary model
accepts_nested_attributes_for :books, :allow_destroy => true, :reject_if=>:all_blank
And now we can do something like this
library=PublicLibrary.find(ID)
library.update_attributes(:books_attributes=>{<bunch of books here>})
And all related books will be updated, some books'll be removed and some new books will be inserted in table books
Now I have some model Book, that doesn't have relation with PublicLibrary:
class Book < ActiveRecord::Base
end
I have an admin panel that show all books in one big-big table and want to update/delete/insert new books just by one click, so I want something like
Book.bulk_update({...books...})
Or working with subset (don't sure is I really need it, but if we can do that...why not to know how?)
books_to_update=Book.where(...).bulk_update({...books...})
Of course Book may have some nested models.
Do you have any ideas?
P.S. Currently I have only idea of having some parent and do update for it...
your {...books...} hash either has multiple books in it for which you want
books.each { |id, book| Book.find(id).update_attributes(book) }
or you want to do a real bulk update (meaning same update to all books in action)
then you can use http://apidock.com/rails/ActiveRecord/Relation/update_all
I have the following models:
class Instance < ActiveRecord::Base
has_many :users
has_many :books
end
class User < ActiveRecord::Base
belongs_to :instance
end
class Book < ActiveRecord::Base
belongs_to :instance
end
I now want to add a BookRevision table, that has the following columns
(id, user_id, version # (auto increment), diff (old book copy),
timestamps)
Logic:
When a book is Created, a record is
added to the BookRevision table, so
we know who created the book in the
first place
When a book is Updated, a record is added with the user_id (could be
a different user), and a new version
, and the old book text, to serve as an archive.
Given that I have the Instance, User, Book table implement in my rails
add, are these the correct steps to make the above come to life?
- Add a migration for the BookRevision table....
rails generate migration AddTableBookRevision user_id:integer
version:integer diff:text
- Then update the models as follows:
class Instance < ActiveRecord::Base
has_many :users
has_many :books
end
class User < ActiveRecord::Base
belongs_to :instance
end
class Book < ActiveRecord::Base
belongs_to :instance
has_many :BookRevisions
end
class BookRevision < ActiveRecord::Base
belongs_to :Book
end
Then in my controller, when adding a new book? Right now I have:
#book = Book.create(params[:book].merge(:instance_id =>
current_user.instance_id))
How do I update that to account for the BookRevision association?
Thanks for helping me out!
You might want to check out something like acts_as_versioned instead of rolling your own. This works in the fashion you've described here, where modifications are saved into a separate but related table.
Keep in mind you will have to apply migrations to your Book and BookRevision table in parallel from that point forward. They must be schema compatible for revisioning to work.
I have built a version tracking system of this sort that used serialized models to avoid having to maintain migrations, as the intent was to preserve the exact state of the model regardless of future modifications via migrations. This has the disadvantage of not being able to roll back to an arbitrary older version because there may be a schema mis-match.