Nested form for has_many through association - ruby

I have two models, reservations and tables, with has_many through relationship between them with a join table and model collections, that has a separate attribute called :units_sold
my Reservation model:
class Reservation < ActiveRecord::Base
has_many :tables, through: :collections
has_many :collections
end
my table model:
class Table < ActiveRecord::Base
has_many :reservations, through: :collections
has_many :collections
end
and finally the collection model:
class Collection < ActiveRecord::Base
belongs_to :table
belongs_to :reservation
end
E.g:
A reservation in my name for 9 people (:units_sold) has 2 tables each with a capacity of 6 and I want 4 people in one table and 5 on the second table
What I have currently is this:
reservation_params
def reservation_params
params.require(:reservation).permit( :name, :total_units, table_ids: [],
collection_attributes: [ :units_sold],
table_attributes: [:capacity, :title])
end
and my form to submit a reservation:
<%= form_for [current_user, #account, #reservation] do |f| %>
<header>
<h1>Make your reservation</h1>
</header>
<%= f.text_field :name, placeholder: "Name" %>
<%= f.number_field :total_units, placeholder: "How many people..." %>
<%= f.fields_for :collections do |c|%>
<% #tables.each do |p| %>
<label for="<%= p.title %>"><%= p.title %></label>
<%= c.number_field :units_sold, placeholder: "People per table..." %>
<%= check_box_tag "reservation[table_ids][]", p.id %>
<% end %>
<% end %>
<%= f.submit "Save" %>
<% end %>
How should I do the reservation_params in the reservation controller? And nest the form to accept :units_sold for each table/reservation association

First, you should define the associations like :
has_many :collections
has_many :reservations, through: :collections
as in, first define collections and then reservations through collections. Similarly, update the associations in the Table model.
Then in the reservation model after defining the associations, add the following line:
accepts_nested_attributes_for :collections
In reservation_params, the key "collection_attributes" and "table_attributes" should be "collections_attributes" and "tables_attributes" respectively.

Related

undefined method `students' for #<Period:0x007fb7fff47360>

I'm trying to add students I created in a school, to a teachers period (class). I'm not looking to create a new student in a period, but rather select students from a list I created in the school. I was able to list the students in a period, but cannot add them to the period. I'm unsure if I use the build method or something different. I'm currently getting an undefined method error and am just unsure which way to go from here.
<p id="notice"><%= notice %></p>
<p>
<strong>Class Name:</strong>
<%= #period.period %>
</p>
<%= link_to 'Delete Period', [#period.teacher, #period],
method: :delete,
data: { confirm: 'Are you sure?' } %>
<h2>Add a student to period</h2>
<%= form_for([#period, #period.students.build]) do |f| %>
<p>
<%= check_box_tag "school[student_ids][]", student.id %>
<%= link_to student.name, edit_school_student_path(#school, student) %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
class Period < ActiveRecord::Base
belongs_to :teacher
has_many :students
end
class Student < ActiveRecord::Base
belongs_to :school
has_many :teachers, through: :periods
end
class Teacher < ActiveRecord::Base
belongs_to :school
has_many :periods
has_many :students, through: :periods
end
class School < ActiveRecord::Base
has_many :teachers, dependent: :destroy
has_many :students, dependent: :destroy
has_many :schoolads, dependent: :destroy
end

Getting error when showing the purchases of the user,when showing the product he bought i get an error for product image and title

This is the relationship i have between User,Gig(product),and Purchase table that records the purchase.
class User < ActiveRecord::Base
has_many :gigs
has_many :purchases, foreign_key: 'buyer_id'
has_many :sales, foreign_key: 'seller_id', class_name: 'Purchase'
end
class Gig < ActiveRecord::Base
has_many :purchases
has_many :buyers, through: :purchases
has_many :sellers, through: :purchases
end
class Purchase < ActiveRecord::Base
belongs_to :gig
belongs_to :buyer, class_name: 'User'
belongs_to :seller, class_name: 'User'
end
To record the purchase i use in my controller
def downloadpage
ActiveRecord::Base.transaction do
if current_user.points >= #gig.pointsneeded
#purchase = current_user.purchases.create(gig: #gig, seller: #gig.user)
if #purchase
current_user.points -= #gig.pointsneeded
#gig.user.points += #gig.pointsneeded
current_user.save
if #gig.user.save
render 'successful_download', locals:{link:#gig.boxlink}
end
end
else
redirect_to :back, notice: "You don't have enough points"
end
end
end
everything works when the buyer buys something from the seller,the points are transferred between accounts,and the buyer gets redirected to the final gig.
In my views i can do
<h1>You downloaded <%= current_user.purchases.count %> boxes</h1>
It will show the number of "gigs" the buyer made.
Now i want to show not just the number,but the title and the picture of the product he bought.This is what i tried
<div class="row experiment">
<% current_user.purchases.each do |gig| %>
<div class="well for-h1-gig-second col-xs-6 col-sm-4 col-lg-3 ">
<%= link_to (image_tag gig.image.url(:medium), :class=>"img-responsive"), gig %>
<h1><%= link_to gig.title, gig %></h1>
</div>
<% end %>
</div>
But it says,that it can not find the image and the title.
so i tried current_user.purchases.gig.each do |gig|
without success.
How do i fix it?
P.S: Please feel free to edit my title,for future readers,i couldn't formulate it better,thank you.
Your main problem is that current_user.purchases.each iterates through purchases - not gigs.
<div class="row experiment">
<% current_user.purchases.each do |purchase| %>
<% gig = purchase.gig %>
<div class="well for-h1-gig-second col-xs-6 col-sm-4 col-lg-3 ">
<%= link_to(image_tag gig.image.url(:medium), :class=>"img-responsive"), gig %>
<h1><%= link_to gig.title, gig %></h1>
</div>
<% end %>
</div>
Also to some of the other issues:
class User < ActiveRecord::Base
has_many :gigs # not going to work.
end
The reason it's not going to work is that the relation between user and gig goes through purchases and the buyer_id and seller_id foreign keys. Rails does not support relations that depend on multiple keys.
If you want to select gigs where the user is either seller or buyer you could use:
Gig.joins(:purchases).where('purchases.buyer_id=? OR purchases.seller_id=?', [current_user.id, current_user.id])
Try adding the association on user:
class User < ActiveRecord::Base
has_many :purchases, foreign_key: 'buyer_id'
has_many :gigs, through: :purchases, source: :buyer
has_many :sales, foreign_key: 'seller_id', class_name: 'Purchase'
end
Then you should be able to loop through current_user.gigs

Unpermitted parameters for nested form many-to-many relationship Rails 4

I have a simple blog app, where I want to be able to create a Post and also create a new Tag for it in the same form, using a nested form.
Post and Tag have a many-to-many relationship, via a join table:
class PostTag < ActiveRecord::Base
belongs_to :post
belongs_to :tag
end
Here's the tag model:
class Tag < ActiveRecord::Base
has_many :post_tags
has_many :posts, :through => :post_tags
validates_presence_of :name
validates_uniqueness_of :name
end
Post model accepts nested attributes for tags:
class Post < ActiveRecord::Base
has_many :post_tags
has_many :tags, :through => :post_tags
accepts_nested_attributes_for :tags
validates_presence_of :name, :content
end
On the posts controller, I permit tags_attributes:
def post_params
params.require(:post).permit(:name, :content, :tag_ids => [], :tags_attributes => [:id, :name])
end
In my form for a new post, where I want to be able to either associate already existing tags (via checkboxes) or create a new one via a nested form using fields_for:
....
<div class="field">
<%= f.collection_check_boxes :tag_ids, Tag.all, :id, :name %><br>
<%= f.fields_for [#post, Tag.new] do |tag_form| %>
<p>Add a new tag:</p><br>
<%= tag_form.label :name %>
<%= tag_form.text_field :name %>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
My error is "Unpermitted parameters: tag":
Parameters: {"utf8"=>"✓", "authenticity_token"=>"dZnCgFxrvuoY4bIUMMxI7kTLEr/R32pUX55wwHZsS4Q=", "post"=>{"name"=>"post title", "content"=>"post content", "tag_ids"=>[""], "tag"=>{"name"=>"new tag"}}, "commit"=>"Create Post"}
Unpermitted parameters: tag
Change:
<%= f.fields_for [#post, Tag.new] do |tag_form| %>
to
<%= f.fields_for(:tags, Tag.new) do |tag_form| %>

Artists Group_by nested attribute Order_date

I have created a functioning e-commerce platform where Members can buy songs. Everything works fine, But I would like to group all of my Orders in my Index Page by Month.
Currently I am able to group each Album with its corresponding Artist, and each Ordered Song to its corresponding Album. But now I would like to group Orders by Month.
How Can I Group Artists by the order_date in my Orders Table, So that everything is organized by Month?
Ex. of what I've like to do
Month 1 Orders
Artist1
Album1 ###List of Albums Corresponding to an Artist
--Song1 (10 0rders)
--Song3 (5 Orders)
Album2
--Song5 (2 Orders) ###Ordered Songs Corresponding to an Album
Month 2 Orders
Artist2
Album1
--Song2 (1 Order)
Artist3
Album3
--Song5 (1 Order)
MODELS
class Order < ActiveRecord::Base
attr_accessible :artist_id, :album_id, :song_id, :user_id, :order_date
belongs_to :song
belongs_to :user
end
class Artist < ActiveRecord::Base
attr_accessible :name
has_many :albums
has_many :songs, :through => :albums
has_many :orders, :through => :songs
end
class Album < ActiveRecord::Base
attr_accessible :name, :artist_id
belongs_to :artist
has_many :songs
has_many :orders, :through => :songs
end
class Song < ActiveRecord::Base
attr_accessible :artist_id, :album_id, :title, :price
belongs_to :album
has_many :orders
end
CONTROLLERS
###How Can I Group Artists by the order_date in my Orders Table?
def index
#artists = Artist.includes(:orders).where('orders.id IS NOT NULL')
end
VIEWS
<% #artists.each do |artist| %> ###Lists All Artists with Orders
<h3><%= artist.name %></h3>
<% artist.albums.each do |album| %> ###Lists All Albums corresponding to Artist
<h4><%= album.name %></h4>
<% album.songs.each do |song| %> ###Lists All Ordered Songs corresponding to Albums
<% if song.orders.count >= 1 %>
(<%= song.orders.count %>)
<%= song.title %>
$<%= song.price %><br>
<% end %>
<% end %>
<% end %>
<% end %>
You get the list of orders ok with this line:
<% #order_months.sort.each do |month, orders| %>
But then you jump back into your full list of artists with this line:
<% #artists.each do |artist| %> ###Lists All Artists with Orders
Instead I think you need something like
<% orders.each do |order| %>
<% order.artists.each do |artist| %>
<% artist.albums.each do |album| %>
<% album.songs.each do |song| %>
<%= song.name %>
To get order.artists you will need to modify your model:
class Order < ActiveRecord::Base
attr_accessible :artist_id, :album_id, :song_id, :user_id, :order_date
belongs_to :song
belongs_to :user
has_many :albums, through: :song
has_many :artists, through: :albums
end
This is how I ended up Solving the Problem
Controller
#orders = Order.find(:all, :order => 'order_date, id', :limit => 50)
Views
<% #orders.sort.group_by { |order| order.order_date.beginning_of_month }.each do |month, orders| %>
<h3><%= month.strftime('%B') %> </h3>
<% orders.group_by { |order| order.song.album.artist }.each do |artist, orders| %>
<h4><%= artist.name %> </h4>
<% orders.group_by { |order| order.song.album }.each do |album, orders| %>
<h5><%= album.name %> </h5>
<% orders.group_by { |order| order.song }.each do |song, orders| %>
<p>(<%= orders.count %>) <%= song.title %> </p>
<p><%= song.price %> </p>
<% end %>
<% end %>
<% end %>
<% end %>

Group Book Orders by Author

I have created a functioning e-commerce platform where Members can buy books. Everything works fine, But I would like to group all of my Orders in my Index Page by Author.
Currently I am able to group each Author, but then every existing Book Order gets listed under each Author. As oppose to only listing the Book Orders corresponding to that Author.
EX. of what I'd like in my Orders Page
###Orders grouped by Authors
Author1
Book1 belongs_to Author1 ###BookOrders grouped by Author
Book2 belongs_to Author1
Book3 belongs_to Author1
Author2
Book1 belongs_to Author2
Book2 belongs_to Author2
Author3
Book1 belongs_to Author3
MODELS
class Order < ActiveRecord::Base
attr_accessible :author_id, :book_id, :user_id, :order_date
belongs_to :book
belongs_to :user
end
class Book < ActiveRecord::Base
attr_accessible : author_id, :title, :price
belongs_to : author
has_many :orders
end
class Author < ActiveRecord::Base
attr_accessible :name
has_many :books
end
CONTROLLER
def index
###How Can I combine this so it Groups Book Orders By Author
###Groups Orders by Author
#orders = Order.find(:all, :order => 'author_id, id', :limit => 50)
#author_orders = #orders.group_by { |order| order.book.author.name }
###Groups Orders by Book
#orders = Order.find(:all, :order => 'author_id, id', :limit => 50)
#book_orders = #orders.group_by { |order| order.book.title }
end
VIEWS
<% #author_orders.each do |author, orders| %>
<h2><%= author %> </h2>
<% #book_orders.each do |book, orders| %>
<h4><%= book %> </h4>
<% end %>
<% end %>
Why not instead:
Model:
class Author < ActiveRecord::Base
attr_accessible :name
has_many :books
has_many :orders, through: :books
end
Controller:
def index
#authors = Author.includes(:orders)
end
View
<% #authors.each do |author| %>
<h2><%= author.name %> </h2>
<% author.orders.each do |order| %>
<h4><%= order.book.title %> </h4>
<% end %>
<% end %>
Update:
To display only those authors who have an order you need unfortunately to do some gymnastics. Also previous includes will not save you completely from N+1 and needs to be improved.
#authors = Author.includes(orders: :books).where('orders.id IS NOT NULL')
You are really close I think.
You just need to get your books from the order that belongs to the author.
Like this...
<% #author_orders.each do |author, orders| %>
<h2><%= author %> </h2>
<% orders.each do |order| %>
<h4><%= order.book %> </h4>
<% end %>
<% end %>

Resources