Artists Group_by nested attribute Order_date - ruby

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 %>

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

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| %>

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 %>

Nested form for has_many through association

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.

query in rails3

In another question that i asked recently i got a really good answer and the code worked... But i do not know exactly why it works... Now i have a similar problem, but don't know how to solve it...?
What i have:
Models
users
questions (with answer_id)
answers
votes (with answer_id and user_id)
model for users:
has_many :questions
has_many :votes
def can_vote_on? (question)
!question.answers.joins(:votes).where('votes.user_id = ?', id).exists?
end
def voted_answer? (question)
(what to do here...?)
end
model for questions:
belongs_to :user
has_many :answers, :dependent => :destroy
accepts_nested_attributes_for :answers, :reject_if => lambda { |a| a[:text].blank? }, :allow_destroy => true
model for answers:
belongs_to :question
has_many :users, :through => :votes, :dependent => :destroy
has_many :votes
model for votes:
belongs_to :answer
belongs_to :user
In my question view i want to make a text bold when the current_used has voted on that specific answer. So how do i finish this:
<% for answer in #question.answers %>
<% if current_user.voted_answer? (#question) %>
<td>
<strong><%= answer.text %></strong>
</td>
<% else %>
<td>
<%= answer.text %>
</td>
<% end %>
<% end %>
Thijs
you may do this
<% for answer in #question.answers %>
<% if answer.votes.index{|vote| vote.user_id == current_user.id} %>
<td>
<strong><%= answer.text %></strong>
</td>
<% else %>
<td>
<%= answer.text %>
</td>
<% end %>
<% end %>
UPDATE
more logical variant create voted_by_user? function in class Answer
class Answer
def voted_by_user?(user)
voits.where('votes.user_id = ?', user.id).exists?
end
end
<% #question.answers.each do |answer| %>
<td>
<% if answer.voted_by_user?(current_user) %>
<strong><%= answer.text %></strong>
<% else %>
<%= answer.text %>
<% end %>
</td>
<% end %>
It sounds like you just want the opposite result of can_vote_on?, i.e. if a user cannot vote on an answer (can_vote_on? returns false), then it means that they already voted (voted_answer? should return true in this case) and vice versa.
One way to solve this is to have voted_answer? return the negation of can_vote_on:
def voted_answer? (question)
!can_vote_on? question
end
Or of course you could use the query you used in can_vote_on? without the negation:
def voted_answer? (question)
question.answers.joins(:votes).where('votes.user_id = ?', id).exists?
end
But I would prefer the first solution due to the DRY principle.
UPDATE
I was wrong about the negation. In this case you're dealing with a specific answer, not all of them.
In your model you'll want the following:
def voted_answer? (answer)
answer.votes.where('votes.user_id = ?', id).exists?
end

Resources