I want to insert multiple data in rails. I'm using postgresql, the scenario is when the form submit it passes client name, email and some personal info, then also pass the desire venue with the date and also the amenities they want (ex. swimming poll, billiard poll and etc.). In my backend I will query :
venue = Venue.find(theVenue_id)
book = venue.books.new(name: client_name, email: client_email and etc)
My question is how can I insert the data in my amenity_books if the had many amenities choosen?
I trie something like this.
ex. amenities_id_choosen = [1,3]
if book.save
amenities_id_choosen.each do |x|
amenity = Amenitiy.find(x)
amenity_book = amenity.amenity_books.create(venue_id: venue.id)
end
I know this is not a good idea to insert data but that was my last choice. Does any body knows how to insert multiple data in 2 model with different data.
Models
class Amenity < ActiveRecord::Base
has_many :categorizations
has_many :venues, through: :categorizations
has_many :amenity_books
has_many :books, through: :amenity_books
end
class Venue < ActiveRecord::Base
has_many :categorizations
has_many :amenities, through: :categorizations
end
class Categorization < ActiveRecord::Base
belongs_to :venue
belongs_to :amenity
end
class Book < ActiveRecord::Base
belongs_to :venue
end
class AmenityBook < ActiveRecord::Base
belongs_to :amenity
belongs_to :venue
belongs_to :book
end
Here's an improved version:
amenities_id_choosen = [1,3]
if book.save
Amenitiy.find(amenities_id_choosen).each do |amenity|
amenity.amenity_books.create(venue_id: venue.id)
end
end
This will result in one SELECT query to find all chosen amenities and one INSERT query for each selected amenity.
Another option is to change your data model, does AmenityBook really need to have a venue? Because it looks like the venue is defined through the Book model already.
Here's a suggestion:
class Book < ActiveRecord::Base
belongs_to :venue
has_many :amenity_books
has_many :amenities, through: :amenity_books
end
class AmenityBook < ActiveRecord::Base
belongs_to :amenity
belongs_to :book
has_one :venue, through: :book
end
The code to create a booking with many amenities:
amenities_id_choosen = [1,3]
book.amenity_ids = amenities_id_choosen
if book.save
# success !
end
Related
I have users table, books table and books_users join table. In the users_controller.rb I am trying extract the users who have filtered_books. Please help me to resolve that problem.
user.rb
has_many :books_users, dependent: :destroy
has_and_belongs_to_many :books, join_table: :books_users
book.rb
has_and_belongs_to_many :users
books_user.rb
belongs_to :user
belongs_to :book
users_controller.rb
def filter_users
#filtered_books = Fiction.find(params[:ID]).books
#users = **I want only those users who have filtered_books**
end
has_and_belongs_to_many does not actually use a join model. What you are looking for is has_many through:
class User < ApplicationRecord
has_many :book_users
has_many :books, through: :book_users
end
class Book < ApplicationRecord
has_many :book_users
has_many :users, through: :book_users
end
class BookUser < ApplicationRecord
belongs_to :book
belongs_to :user
end
If you want to add categories to books you would do it by adding a Category model and another join table. Not by creating a Fiction model which will just create a crazy amount of code duplication if you want multiple categories.
class Book < ApplicationRecord
has_many :book_users
has_many :users, through: :book_users
has_many :book_categories
has_many :categories, through: :book_categories
end
class BookCategory < ApplicationRecord
belongs_to :book
belongs_to :category
end
class Category < ApplicationRecord
has_many :book_categories
has_many :books, through: :book_categories
end
If you want to query for users that follow a certain book you can do it by using an inner join with a condition on books:
User.joins(:books)
.where(books: { title: 'Lord Of The Rings' })
If you want to get books that have a certain category:
Book.joins(:categories)
.where(categories: { name: 'Fiction' })
Then for the grand finale - to query users with a relation to at least one book that's categorized with "Fiction" you would do:
User.joins(books: :categories)
.where(categories: { name: 'Fiction' })
# or if you have an id
User.joins(books: :categories)
.where(categories: { id: params[:category_id] })
You can also add an indirect association that lets you go straight from categories to users:
class Category < ApplicationRecord
# ...
has_many :users, though: :books
end
category = Category.includes(:users)
.find(params[:id])
users = category.users
See:
The has_many :through Association
Joining nested assocations.
Specifying Conditions on Joined Tables
From looking at the code i am assuming that Book model has fiction_id as well because of the has_many association shown in this line Fiction.find(params[:ID]).books. There could be two approaches achieve this. First one could be that you use #filtered_books variable and extract users from it like #filtered_books.collect {|b| b.users}.flatten to extract all the users. Second approach could be through associations using fiction_id which could be something like User.joins(:books).where(books: {id: #filtererd_books.pluck(:id)})
class Sample
has_many :pictures
end
class Picture < ApplicationRecord
belongs_to :imageable, polymorphic: true
belongs_to :sample
end
class Employee < ApplicationRecord
has_many :pictures, as: :imageable
end
class Product < ApplicationRecord
has_many :pictures, as: :imageable
end
What should be the association to get all product or employee of a given sample.
Sample.first.pictures.map(&:imageable). I want to get it as an activerecord association.
Workaround:
class Sample
has_many :pictures
has_many :imageable_employees, through: :pictures, source: :imageable, source_type: 'Employee'
has_many :imageable_products, through: :pictures, source: :imageable, source_type: 'Product'
end
Usage:
sample = Sample.first
employees = sample.imageable_employees
products = sample.imageable_products
...see docs
Explanation:
Sample.first.pictures.map(&:imageable). I want to get it as an activerecord association.
... is I don't think it's possible, but you can still get them all as an Array instead. The reason is that there is no table (model) that corresponds to the imageable association, but that it corresponds to ANY model instead, which complicates the SQL query, and thus I don't think it's possible.
As an example, consider the following query:
imageables_created_until_yesterday = Sample.first.something_that_returns_all_imageables.where('created_at < ?', Time.zone.now.beginning_of_day)
# what SQL from above should this generate? (without prior knowledge of what tables that the polymorphic association corresponds to)
# => SELECT "WHAT_TABLE".* FROM "WHAT_TABLE" WHERE (sample_id = 1 AND created_at < '2018-08-27 00:00:00.000000')
# furthermore, you'll notice that the SQL above only assumes one table, what if the polymorphic association can be at least two models / tables?
Alternative Solution:
Depending on the needs of your application and the "queries" that you are trying to do, you may or may not consider the following which implements an abstract_imageable (a real table) model for you to be able to perform queries on. You may also add more attributes here in this abstract_imageable model that you think are "shared" across all "imageable" records.
Feel free to rename abstract_imageable
class Sample
has_many :pictures
has_many :abstract_imageables, through: :pictures
end
class Picture
belongs_to :sample
has_many :abstract_imageables
end
# rails generate model abstract_imageable picture:belongs_to imageable:references{polymorphic}
class AbstractImageable
belongs_to :picture
belongs_to :imageable, polymorphic: true
end
class Employee < ApplicationRecord
has_many :abstract_imageables, as: :imageable
has_many :pictures, through: :abstract_imageables
end
class Product < ApplicationRecord
has_many :abstract_imageables, as: :imageable
has_many :pictures, through: :abstract_imageables
end
Usage:
sample = Sample.first
abstract_imageables = sample.abstract_imageables
puts abstract_imageables.first.class
# => AbstractImageable
puts abstract_imageables.first.imageable.class
# => can be either nil, or Employee, or Product, or whatever model
puts abstract_imageables.second.imageable.class
# => can be either nil, or Employee, or Product, or whatever model
# your query here, which I assumed you were trying to do because you said you wanted an `ActiveRecord::Relation` object
abstract_imageables.where(...)
When I developed my first sandbox application, I wanted to get some records for relational table.
User.rb:
class User < ActiveRecord::Base
#has many followed articles
has_many :follow_articles
And FollowArticle model:
class FollowArticle < ActiveRecord::Base
belongs_to :user
belongs_to :article
end
And Article model:
class Item < ActiveRecord::Base
has_many :follow_articles
end
I want to get all followed articles of a user so in my controller I have:
#articles = current_user.follow_articles
which gave me:
ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_FollowArticle:x3014X2
In my view I can iterate over these articles:
<% #articles.each do |article| %>
<%= article.article.name %>
<% end %>
which works perfectly.
Can I do this in this way to get an Articles array instead of a FollowArticles array, something like:
#items = current_user.follow_articles
to return articles instead of followArticles?
Use has_many :through.
From the Guide:
A has_many :through association is often used to set up a many-to-many connection with another model. This association indicates that the declaring model can be matched with zero or more instances of another model by proceeding through a third model. For example, consider a medical practice where patients make appointments to see physicians. The relevant association declarations could look like this:
class Physician < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ApplicationRecord
belongs_to :physician
belongs_to :patient
end
class Patient < ApplicationRecord
has_many :appointments
has_many :physicians, through: :appointments
end
So, fully connecting the dots...
#User.rb
class User < ActiveRecord::Base
has_many :follow_articles
has_many :followed_articles, through: :follow_articles
end
I have 3 models: User, Order and Car and I have question because I don't know what relationships between these models will be the best. Only requirement is that only one car per user in order.
A user can have many orders, and therefore, many cars through those orders.
class User < ActiveRecord::Base
has_many :orders
has_many :cars, through: :orders
end
An order belongs to a user and a car.
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :car
end
A car has one order.
class Car < ActiveRecord::Base
has_one :order
end
So you need one on one relationship between order and car and then back to order and customer one relationship. Something below should do the trick.
class Car < ActiveRecord::Base
has_one :order
has_one :customer, through: :order
end
class Order < ActiveRecord::Base
belongs_to :car
belongs_to :customer
end
class Customer < ActiveRecord::Base
has_one :order
has_one :car , through: :order
end
But i will suggest the has_many relationship by the looks of the model name, but you know better your problem than me.
I have three tables: illnesses, symptoms and a third table to map the relationship between the first two, called symptom_illness.
This third table has symptom_id, illness_id and its own id
I need a way to show, for example, all symptoms of a given "Common Cold" illness. In this example, "Common Cold" has an id of 1 and its symptoms have ids of 1 through 5.
This means that symptom_illness has 5 entries, where:
symptom_illness.illness_id = 1, symptom_id = 1
symptom_illness.illness_id = 1, symptom_id = 2
symptom_illness.illness_id = 1, symptom_id = 3
And so on. I need a way to display, in a single page, all the symptoms that have the same illness_id but I can't seem to find a way how to.
EDIT 1: My classes are related as such:
Symptom:
has_many :symptom_illness
has_many :illnesses, through: :symptom_illness
And similar for Illness.
Illness_symptom has belongs_to :symptom and belongs_to :illness
You have three models
class Symptom
has_many :symptom_illnesses
has_many :illnesses, through: :symptom_illnesses
end
class SymptomIllness
belongs_to :illness
belongs_to :symptom
end
class Illness
has_many :symptom_illnesses
has_many :symptoms, through: :symptom_illnesses
end
You can easily access al illness symptoms with something like that:
Illness.find(1).symptoms.each do |symptom|
# do something with this symptom
end
What do you want to show in the page?
If the symptom has a name attribute you can initialize a
#symptoms = Illness.find(1).symptoms
array in controlller and in the page you do something like
<% #symptomps.each do |symptom| %>
<% = symptom.name %>
<% end %>
You should use a has_many through: relationship.
class Illness < ActiveRecord::Base
has_many :symptom_illness
has_many :symptom, through: :symptom_illness
end
class SymptomIllness < ActiveRecord::Base
belongs_to :symptom
belongs_to :illness
end
class Symptom < ActiveRecord::Base
has_many :symptom_illness
has_many :illness, through: :symptom_illness
end
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
Class Symptom < ActiveRecord::Base
belongs_to :symptom_illness
has_many :ilnesses, through: symptom_illness
end
class SymptomIllness < ActiveRecord::Base
belongs_to :symptom
belongs_to :illness
scope :ilness, ->(*i) {
where(ilness_id: i.flatten.compact.uniq
}
end
class Illness < ActiveRecord::Base
belongs_to :symptom_illness
has_many :symptoms, through: :symptom_illness
end
Ilness.find(1).symptoms