Rails how iterate has_one though? - mysql

This is the scenario:
so, the product did not have any relation with feedback, but the order has
and i would like to show the feedbacks as belongs to products
model FEEDBACK
has_one :order
has_one :product, through: :order
model ORDER
belongs_to :product, touch: true
belongs_to :feedback
model PRODUCT
has_many :feedbacks
has_many :orders
i'm would like to get the feedbacks of the product on a loop
for exemple
controller HOME
#total_feedbacks = Feedback.joins(:product).where('products.id = ?', #product.id).where('buyer_feedback_date is not null').count
#average_rating_from_buyers = Feedback.joins(:product).where('products.id = ?', #product.id).where('buyer_feedback_date is not null').rated(Feedback::FROM_BUYERS).average(:buyer_rating)
view HOME
<table id="posts" class="product_table">
<tbody class="page">
<tr>
<% #products.last(22).each do |product|%>
<td>
<%=link_to product_path(product.id), :class=>"product" do %>
<span class="productName">
<%=product.name %></span>
<span class="price"><%=number_to_currency(product.price, :unit=> "R$") %></span>
<% if product.vitrine.feedbacks.present? %>
<div class="productFeeback">
<div><%= #average_rating_from_buyers %>"></div>
<%=#total_feedbacks %>
</div>
<% end %>
<% end %>
</td>
<% end %>
</tr>
</tbody>
</table>
with this code i'm getting
undefined method `id' for nil:NilClass
someone have a hint to spare? thank's

On your Product model, try:
has_many :feedbacks, through: :orders
For the "Undefined method id" error, it would help if you could include a bit more of your stack trace.
Just based on the example code, I think it would have to be happening in the controller. #product.id is being referenced, but I don't see #product being set.

Related

Rails nested forms not rendering a proper name or id for the inputs

I'm trying to render a nested form but the main problem is that the inputs generated haven't got a proper id/name. They should contain something like *_attributes but they don't.
Main model - Menu model
class Menu < ApplicationRecord
belongs_to :company
has_many :menu_days, :dependent => :destroy
accepts_nested_attributes_for :menu_days, allow_destroy: true, reject_if: :all_blank
has_and_belongs_to_many :dishes
has_and_belongs_to_many :locations
paginates_per 10
end
Nested model - MenuDay model
class MenuDay < ApplicationRecord
belongs_to :menu
validates :day, presence: true
end
New action in menus controller
def new
#menu = Menu.new
#frequencies = ##frequencies
##menu_days.each do |menu_day|
#menu.menu_days.build(:day => menu_day.day)
end
end
New.html.erb
<% menu.menu_days.each do |menu_day| %>
<%= f.fields_for :menu_days, menu_day do |menu_days_form| %>
<div>
<%= menu_days_form.check_box :day, class: "form-checkbox-nutri" %>
<%= menu_days_form.label :day, menu_day.day %>
</div>
<% end %>
<% end %>
This code is rendering the nested form, but the inputs code are something like this:
<div>
<input name="menu[menu_days][day]" type="hidden" value="0"><input class="form-checkbox-nutri" type="checkbox" value="1" name="menu[menu_days][day]" id="menu_menu_days_day">
<label for="menu_menu_days_day">Daily</label>
</div>
According to what I've read in the official documentation (https://guides.rubyonrails.org/form_helpers.html#building-complex-forms), names and ids should contain _attributes suffix. Besides, they should contain as well some kind of unique id. To sum up, they should be something like menu[menu_days_attributes][0][day]. But, as you can see, they're not.
Also I already tried with more basic fields_for implementations with same result. For instance (avoiding the external loop):
<%= f.fields_for :menu_days do |menu_days_form| %>
<div>
<%= menu_days_form.check_box :day, class: "form-checkbox-nutri" %>
<%= menu_days_form.label :day %>
</div>
<% end %>
In this case, it didn't even iterate properly and it only showed 1 block instead of 8.
What am I missing?
Thanks!

Ruby on rails: How to display information from another table?

Updated: 22/08/2019
This is working now. Thanks for feedback and help!
Image of Benefit list: List Display <-- Needed to params permit benefit_ids
Old Version: 21/08/2019
I have set up many to many associations but can't get the data table name. I can get the ID but it won't allow me to display the other fields information.
I have looked in the controller and added to permit benefit_ids but not sure if I should add anything else to it.
exercisetypes(Index.html.erb)
--- Old code (21/08/2019)
<tbody>
<% #exercisetypes.each do |exercisetype| %>
<tr>
<td><%= exercisetype.name %> </td>
<td><%= exercisetype.benefits.name %> </td>
...
---
New code (22/08/2019)
<tbody>
<% #exercisetypes.each do |exercisetype| %>
<tr>
<td> <%= exercisetype.name %> </td>
<td>
<ul>
<% exercisetype.benefits.each do |benefit| %>
<li><%= benefit.name %></li>
<% end %>
</ul>
</td>
<% end %>
...
_form.html.erb(Gem: simple form)
<% f.association :benefits, as: :check_boxes %>
Models
exercisetype.rb
has_many :exercisetype_benefits, dependent: :destroy
has_many :benefits, :through => :exercisetype_benefits
benefit.rb
has_many :exercisetype_benefits
has_many :exercisetypes, :through => :exercisetype_benefits
exercisetype_benefit.rb
belongs_to :exercisetype
belongs_to :benefit
The table displays the model name Benefit. There are no error messages but I am not sure how to display the name of the benefit.
exercisetype.benefits is a collection:
# index.html.erb
<ul>
<% exercisetype.benefits.each do |benefit| %>
<li><%= benefit.name %></li>
<% end %>
</ul>
Benefits belongs to exercisetype model, so you need to iterate over benefits to access the attributes. Check this:
<tbody>
<% #exercisetypes.each do |exercisetype| %>
<tr>
<td><%= exercisetype.name %> </td>
<td>
<ul>
<% exercisetype.benefits.each do |benefit| %>
<li><%= benefit.name %></li>
<% end %>
</ul>
</td>
</tr>
<% end %>
</table>
Exercise has_many benefits which mean when you do exercise.benefits it will return a collection of benefits object so you need to iterate through it.
Your collection will look like
`#<ActiveRecord::Associations::CollectionProxy [#<Benefit id: 1, name: "Good Health">, #<Benefit id: 2, name: "Blood flow">]>`
So you need to iterate through it like.
<% exercisetype.benefits.each do |benefit| %>
<li><%= benefit.name %></li>
<% end %>

Rails: Issue with recieving nested forms with has many through join

I seem to be having a problem with receiving products through my join table, it's giving me a strange error as it seems to be receiving no ID for my order. I can only assume that this is because the order has not been created yet, but I am creating the order during this step anyway, so the order doesn't have an ID yet. So this is my problem.
Here is the error I recieve:
ActiveRecord::RecordNotFound in OrdersController#create
Couldn't find Product with ID=1 for Order with ID=
Rails.root: /BillingSystem
Application Trace | Framework Trace | Full Trace
app/controllers/orders_controller.rb:10:in `new'
app/controllers/orders_controller.rb:10:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"jE2wdERoxE7PKwBhN60KAfguxwAq8qdW4wbru51SMFg=",
"order"=>{"client_id"=>"1",
"products_attributes"=>{"1368396234677"=>{"id"=>"1",
"_destroy"=>"false"}}},
"commit"=>"Create Order"}
Show session dump
Show env dump
Response
Headers:
None
New Order View:
<% if current_user %>
<div id="dashboard">
<div id="logo"></div>
<table id="go_back_link_container">
<tr>
<td>
<div class="go_back_link">
<%= link_to "<- Go Back", "/orders/view" %>
</div>
</td>
<td>
<div id="user_display">
Logged in as <%= current_user.email %>.
<%= link_to "Log out", log_out_path %>
</div>
</td>
</tr>
</table>
<%= form_for #order, method: :post do |f| %>
<% if #order.errors.any? %>
<div class="error_messages">
<% for message in #order.errors.full_messages %>
* <%= message %> <br>
<% end %>
</div>
<% end %>
<p>
<%= f.label 'Select The Client' %><br />
<%= select :order, :client_id, Client.all().collect { |c| [ (c.firstname + " " + c.surname), c.id ] } %>
</p>
<%= f.fields_for :products do |pf| %>
<% #render 'product_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Add Product", f, :products %>
<p class="button"><%= f.submit %></p>
<% end %>
<% flash.each do |name, msg| %>
<%= content_tag :div, "* " + msg, :id => "flash_#{name}" %><br />
<% end %>
<div id="copyright-notice"><div id="copyright_border">Copyright © Conner McCabe, all rights reserved.</div></div>
</div>
<% else %>
<script type="text/javascript">
window.location="<%= root_url %>"
</script>
<% end %>
Order Model:
class Order < ActiveRecord::Base
has_many :orderedproducts
has_many :products, through: :orderedproducts
has_one :client
attr_accessible :client_id, :order_total, :delivery_date, :products, :products_attributes
accepts_nested_attributes_for :products, :allow_destroy => true
before_save :generate_total
def generate_total
self.order_total = self.products.map(&:product_price).sum
end
end
Orders Controller:
class OrdersController < ApplicationController
def view
#orders = Order.all
end
def new
#order = Order.new
end
def create
#order = Order.new(params[:order])
if #order.save
redirect_to '/orders/view', :notice => "Order Created!"
else
render "new"
end
end
end
Product Fields Partial:
<fieldset>
<%= f.select :id, Product.all().collect {|p| [ p.product_name, p.id ] } %>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
Products Model:
class Product < ActiveRecord::Base
#This line makes these elements accessible outside of the class.
attr_accessible :product_name, :product_price, :product_quantity, :product_supplier
has_many :orderedproducts
has_many :orders, through: :orderedproducts
#These attributes ensure that the data entered for each element is valid and present.
validates_presence_of :product_name
validates_presence_of :product_price
validates_numericality_of :product_price
validates_presence_of :product_quantity
validates_numericality_of :product_quantity
validates_presence_of :product_supplier
end
Application Helper:
module ApplicationHelper
def link_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize + "_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
end
Ordered Products Model:
class Orderedproduct < ActiveRecord::Base
attr_accessible :order_id, :product_id, :quantity_ordered
belongs_to :order
belongs_to :product
end
I have listed every possible file that could contain an error, I know it's a bit excessive, but it's everything that is to do with it and better I include it than not at all.
I also followed this railscast guide: http://railscasts.com/episodes/196-nested-model-form-revised
To get to where I am, I edited it slightly so that it was suitable for my application.
Thanks in advance.
We had a similar issue on a project, except the relation was singular. The problem is that ActiveRecord is looking for an existing association; something like order.products.find(1). Since order is as new record this doesn't work.
You could create your own products_attributes= method and define the correct behaviour. But I think that you could just use nested attributes for the join model (Orderedproduct) instead of Product.
class Order
accepts_nested_attributes_for :orderedproducts
end
Then adjust the form fields appropriately. In the new form
f.fields_for :products do |pf| becomes f.fields_for :orderedproducts do |pf|
In the fields partial
<%= f.select :id, Product.all().collect {|p| [ p.product_name, p.id ] } %> becomes <%= f.select :product_id, Product.all().collect {|p| [ p.product_name, p.id ] } %>

Select data from two tables and listing

I have following structure:
class User < ActiveRecord::Base
has_many :Hobbies, :dependent => :destroy
accepts_nested_attributes_for :hobbies, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
class Hobby < ActiveRecord::Base
belongs_to :User
end
In my Users_controller.rb
def index
#data = User.all(:joins => :hobbies)
end
In index.html.erb
<% for item in #data %>
<tr>
<td><%= item.id %></td> #from table Users
<td><%= item.hobby_name %></td> #from table Hobbies
</tr>
<% end %>
And this gives me an error undefined method `hobby_name' for # User:0x103cf7480>
I thought that I have that associations right, but this error makes confused... Can you help me someone, please, where could be a problem?
You must specify the relation, your object doesn't have an attribute called hobby_name, it has an association to multiple hobbies, and each hobby has an attribute called hobby_name
So:
<% item.hobbies.each do |h| %>
<%= h.hobby_name %>
<% end %>

Rails 3 with joins among 2 tables

I have 2 models, car and registrations.
class Car < ActiveRecord::Base
belongs_to :Registration
end
class Registration < ActiveRecord::Base
has_many :cars, :dependent => :destroy
accepts_nested_attributes_for :cars, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
In CarsController:
def index
#cars = Car.all
#cars2 = Car.all(:joins => :Registration)
end
In view:
<% #cars.each do |car| %>
<tr>
<td><%= car.twitter %></td>
<td><%= car.facebook %></td>
<td>
<% #cars2.Registration.each do |h| %> #here is my problem
<%= h.email %>
<% end %>
</td>
</tr>
<% end %>
This is my statement of cars. I am trying to print for every car owner's email. The email is in table Registration (model registration). I don't know how to make a query to database, that I want to get email from table Registrations, when column registration_id in table Cars == id column of table Registrations...
So I would like to ask you, if you have a tip, how to do...
You have got your associations in capital letters. It should be in small like this
class Car < ActiveRecord::Base
belongs_to :registration
end
Also you dont have to assign 2 variables in the controller
def index
#cars = Car.includes(:registration)
end
and in the view
<% #cars.each do |car| %>
<tr>
<td><%= car.twitter %></td>
<td><%= car.facebook %></td>
<td>
<%= car.registration.email %> #here is my problem
</td>
</tr>
<% end %>
Use this instead to fetch the email:
<%= car.registration.email %>
If you want eager loading, then use the following line in your controller instead:
#cars = Car.includes(:registration)
There's no need for #cars2.