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

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

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.

Nested attributes that do not belong to the current object using has_many :through

My end goal is to be able to add costumes to an agreement in the agreement view, regarless of whether or not they exist in the Costume database yet. My main difficulty is that a costume does not belong to an agreement, they exist independently but can be added to an agreement. If a new costume is added that isn't in the Costume database, it will add it to the database. Is there a way to do this? I can't find a tutorial about this anywhere. If I could get the controller from this post, I think that is all I need. I just need to create one costume every time the form is displayed. Thanks so much.
My models are as follows:
# app/models/agreement.rb
class Agreement < ActiveRecord::Base
has_and_belongs_to_many :costumes, join_table: :agreement_costumes
accepts_nested_attributes_for :costumes, :reject_if => :all_blank
end
# app/models/costume.rb
class Costume < ActiveRecord::Base
has_and_belongs_to_many :agreements, join_table: :agreement_costumes
end
# app/models/agreement_costume.rb
class AgreementCostume < ActiveRecord::Base
belongs_to :agreement
belongs_to :costume
end
My agreement controller is as follows:
class AgreementsController < ApplicationController
before_action :set_agreement, only: [:show, :edit, :update, :destroy]
# Some methods ommitted
# GET /agreements/new
def new
#agreement = Agreement.new
#agreement.costumes.build
#costumes = Costume.all
end
private
# Use callbacks to share common setup or constraints between actions.
def set_agreement
#agreement = Agreement.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def agreement_params
params.require(:agreement).permit(:name, :phone, :email, :mailbox, :wesid, :title, :start, :end, :due, :financer, :employee, :costumes_attributes => [:cid, :description, :wd, :back, :photo])
end
:end
And finally, the agreement view
<%= form_for(#agreement) do |f| %>
<% if #agreement.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#agreement.errors.count, "error") %> prohibited this agreement from being saved:</h2>
<ul>
<% #agreement.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<!-- Agreement fields omitted -->
<%= f.fields_for :costumes do |c| %>
<div class="field">
<%= c.label :cid %><br>
<%= c.number_field :cid %>
</div>
<div class="field">
<%= c.label :description %><br>
<%= c.text_field :description %>
</div>
<!-- etc with costume fields -->
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You need accepts_nested_attributes_for in your Agreement controller if you want to create new costumes there.
class Agreement < ActiveRecord::Base
has_many :agreement_costumes
has_many :costumes, through: :agreement_costumes
accepts_nested_attributes_for :costumes, :reject_if => :all_blank, :allow_destroy => :false,
end
and then in the agreements#new action in your Agreements controller you build a costume entry
def new
#agreement = Agreement.new
#agreement.costumes.build
#costumes = Costumes.all
end
#agreement.costumes.build creates a blank instance of a costume, related to this agreement. You then access the params of that costume in the form using :costumes Don't forget to whitelist your nested params in your Agreements controller:
def agreement_params
params.require(:agreement).permit(:name, :phone, :email, :mailbox, :wesid,
:title, :start, :end, :due, :financer, :employee, costumes_attributes[:name, :price, :id])
end
Now your form has to have a place to choose existing costumes from a list and/or add a new one.
<%= f.label :costumes, "Costumes" %>
<%= f.collection_select :costumes, :agreement_id, :id, :name, price, {}, {multiple: true} %>
<strong>Add a new costume</strong>
<%= f.fields_for :costumes do |c|
<%= c.label :name %>
<%= c.text_field :name %>
<br>
<%= c.label :price %>
<%= c.number_field :price %>
<br>
<% end %>
This should get you most of the way there. I've had to guess at some of your code, so this isn't going to be a cut and paste answer. You'll need to build what you can off of this and probably do a little more Googling here and there. If you wanted to have a popup form to add a costume to the list on the fly and then be able to choose it in the collection_select, you would have to turn on Turbo_links in your app, create a Javascript popup form. Then use AJAX to submit the form, save the costume to the database, run another .js.erb file that would then update the collection_select text list using a reload of just that list via your Javascript. It's actually probably easier than having a new costume form nested in this form.

Resources