HABTM Association Build - ruby-on-rails

I need propagate this values in :departaments_products table: , but I received the error:
I'm using Rails 4
NoMethodError in Products#new
undefined method `departament_id' for #<Product:0x007f916d35d648>
view.html.erb:
<%= form_for(#product) do |f| %>
<% if #product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% #product.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :price %><br>
<%= f.text_field :price %>
</div>
<%= f.collection_select(:departament_id, Departament.all, :id, :name, {:include_blank => true}) %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Products_controller:
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
#products = Product.all
end
# GET /products/1
# GET /products/1.json
def show
#product = Product.find( params[:id] )
end
# GET /products/new
def new
#product = Product.new
end
# GET /products/1/edit
def edit
end
# POST /products
# POST /products.json
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Produto criado com sucesso' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:name, :price)
end
end
Models:
class Departament < ActiveRecord::Base
has_and_belongs_to_many :products
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :departaments
end
Migration:
class AddProductsAndDepartaments < ActiveRecord::Migration
def change
create_table :departaments_products do |t|
t.references :product, :departament
end
end
end

As its a HABTM association, logically you should be selecting multiple departament_ids for a single product. That said, you should include multiple: true option in the collection_select for departament_ids (Notice departament_ids in plural) in your view code:
<%= f.collection_select(:departament_ids, Departament.all, :id, :name, {include_blank: true}, {multiple: true}) %>
Currently, you are accessing it as departament_id (Notice singular) BUT as per HABTM association you get a method named departament_ids (Notice plural) and NOT departament_id which is why you receive error as NoMethodError in Products#new undefined method 'departament_id'
Once you are done with this change, you need to permit the departament_ids field in ProductsController as below:
def product_params
params.require(:product).permit(:name, :price, :departament_ids => [])
end
:departament_ids => [] is used because multiple selection is allowed for departament_ids and so you would receive it as an Array in params hash upon form submission.

Try departament_ids
For has_many => departament_ids
For has_one => departament_id

Related

Cannot fill out price field in my editing section using Ruby on Rails

I have just recently tried to implement 'Stripe' to take payments on my website. However, I am have a certain issue trying to update the price on the products.
This is my payments controller.
class PaymentsController < ApplicationController
def create
token = params[:stripeToken]
#product = Product.find(params[:product_id])
#user = current_user
# Create the charge on Stripe's servers to charge the user's card
begin
charge = Stripe::Charge.create(
amount: (#product.price*100).to_i,
currency: "eur",
source: token,
description: params[:stripeEmail]
)
if charge.paid
Order.create!(product_id: #product.id, user_id: #user.id, total: #product.price.to_i)
UserMailer.order_placed(#user,#product).deliver_now
end
rescue Stripe::CardError => e
body = e.json_body
err = body[:error]
flash[:error] = "Unfortunately, there was an error processing your payment: #{err[:message]}"
end
redirect_to product_path(#product), notice: 'Thank you for your order!'
end
end
My products model
class Product < ApplicationRecord
has_many :orders
has_many :comments
validates :name, presence: true
validates :price, presence: true
def price_show
"€ %.2f" % (self[:price]/100.0)
end
def price
self[:price]
end
def self.search(search_term)
Product.where("name LIKE ?", "%#{search_term}%")
end
# Called by <%= #product.highest_rating_comment %>
def highest_rating_comment
comments.rating_desc.first
end
def average_rating
comments.average(:rating).to_f
end
end
and my partial form.
<%= form_with(model: #product, local: true) do |form| %>
<% if #product.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% product.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :description %>
<%= form.text_area :description %>
</div>
<div class="field">
<%= form.label :image_url %>
<%= form.text_field :image_url %>
</div>
<div class="field">
<%= form.label :color %><br>
<%= form.text_field :color %>
</div>
<div class="field">
<%= form.label :price %>
<%= form.text_field :price %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
The problem I am having is that when I enter in the price, I will be getting the 'undefined error" on both of these lines, to which it will say "did you mean #product?".
div id="error_explanation">
<h2><%= pluralize(product.errors.count, "error") %> prohibited this product from being saved:</h2>
<ul>
<% product.errors.full_messages.each do |message| %>
I change both the lines accordingly, the page loads. However, when I try to enter the price on the page, I will get an error message, stating that the price 'cannot be blank', even though I am entering a numerical value in the field.
My products controller code is as follows.
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
if params[:q]
search_term = params[:q]
#products = Product.search(search_term)
else
#products = Product.limit(4)
end
end
# GET /products/1
# GET /products/1.json
def show
#comments = #product.comments.order("created_at DESC")
#comments = #comments.paginate(:page => params[:page], :per_page => 2)
end
# GET /products/new
def new
#product = Product.new
end
# GET /products/1/edit
def edit
end
# POST /products
# POST /products.json
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:name, :description, :image_url, :color)
end
end
Am relatively new to rails so sorry if this is a silly question but any help would be greatly appreciated.
price 'cannot be blank'
You should whitelist price in the product_params method to fix the validation error (i.e, price 'cannot be blank') and to able to save the product with its price successfully.
def product_params
params.require(:product).permit(:name, :description, :image_url, :color, :price)
end
Reason for the error:
Since you didn't whitelisted price attribute, it will treated as unpermitted params and won't be included in the params hash while saving the #product. And as save triggers the validations, #product fails the validation check on price resulting in that error.

Rails 5 error accepts_nested_attributes_for in polymorphic

I have an error when I try create a product: "Cannot build association 'type_data'. Are you trying to build a polymorphic one-to-one association?"
I don't know what is happend. I saw a lot examples with the same code but mine doesn't work.
Here my product.rb
class Product < ApplicationRecord
belongs_to :type_data, polymorphic: true
accepts_nested_attributes_for :type_data, allow_destroy: true
end
Here my hotel_room.rb
class HotelRoom < ApplicationRecord
has_one :product, as: :type_data, dependent: :destroy
has_many :rates
accepts_nested_attributes_for :rates, allow_destroy: true
end
My products/_form.html.erb
<%= f.fields_for :type_data do |builder| %>
<%= render "edit_hotel_account_fields", f: builder %>
<% end %>
My products/_edit_account_fields.heml.erb
<%= f.fields_for :rates do |builder| %>
<%= render 'rate_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Add rate", f, :rates %>
My products/_rate_fields.html.erb
<div class="form-group">
<label><%= t('products.new.rates.double_price') %></label>
<%= f.number_field :double_price, step: 0.1, class: 'form-control' %>
</div>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
And this is all my products_controller.rb
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
#products = Product.all
end
# GET /products/1
# GET /products/1.json
def show
end
# GET /products/new
def new
#product = Product.new
end
# GET /products/1/edit
def edit
end
# POST /products
# POST /products.json
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to products_path, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: #product }
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { render :show, status: :ok, location: #product }
else
format.html { render :edit }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :no_content }
end
end
# AJAX cargas más fechas
def date_range
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:status, :provider_id, :commission, :title, :commercial_title, :title_seo, :description, :seo_description, :slug_web, :slug_redirection, :services, :info, :province, :state, :city, :country, :cancel_conditions, :limit_children_age, :special_alert, :notes, :stock, :iva, :minimum_advance, type_data_attributes: [:room_stock, :room_service, :_destroy, rates_attributes: [:title, :start_date, :end_date, :hotel_room_id, :individual_price, :double_price, :child_bed_price, :adult_bed_price, :adult_breakfast_price, :adult_medium_price, :adult_complete_price, :child_breakfast_price, :child_medium_price, :child_complete_price, :_destroy]], dates: {}, map: {}, address_autocomplete: {})
end
end
Do anyone know what is happend?
Thanks!
As Hotel model has one Product via polymorphic,
class HotelRoom < ApplicationRecord
has_one :product, as: :type_data, dependent: :destroy
accepts_nested_attributes_for :product, allow_destroy: true
accepts_nested_attributes_for :rates, allow_destroy: true
....
end
In hotel_rooms controller new action
def new
#hotel_room = HotelRoom.new
#hotel_room.build_product
end
In Hotel view form
<%= form_for(#hotel_room) do |f| %>
....
<%= f.fields_for(:product) do |p| %>
....
<% end %>
<% end %>
Note:
If you have common data between HotelRoom and Product, then you need to introduce another model like TypeData and set it polymorphic.

Rails 4 Nested Model : Not working

I was trying to work with simple nested models & forms but have failed eventually. I don't understand what wrong am I doing? Trying to implement simple nested model. A parent having many child. Can anyone please help me out. Thanks.
Here are the models:
parent.rb
class Parent < ActiveRecord::Base
has_many :childs
accepts_nested_attributes_for :childs
end
child.rb
class Child < ActiveRecord::Base
belongs_to :parent
end
parents_controller.rb
class ParentsController < ApplicationController
before_action :set_parent, only: [:show, :edit, :update, :destroy]
# GET /parents
# GET /parents.json
def index
#parents = Parent.all
end
# GET /parents/1
# GET /parents/1.json
def show
end
# GET /parents/new
def new
#parent = Parent.new
#parent.childs.new
end
# GET /parents/1/edit
def edit
end
# POST /parents
# POST /parents.json
def create
#parent = Parent.create(parent_params)
respond_to do |format|
if #parent.save
format.html { redirect_to #parent, notice: 'Parent was successfully created.' }
format.json { render :show, status: :created, location: #parent }
else
format.html { render :new }
format.json { render json: #parent.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /parents/1
# PATCH/PUT /parents/1.json
def update
respond_to do |format|
if #parent.update(parent_params)
format.html { redirect_to #parent, notice: 'Parent was successfully updated.' }
format.json { render :show, status: :ok, location: #parent }
else
format.html { render :edit }
format.json { render json: #parent.errors, status: :unprocessable_entity }
end
end
end
# DELETE /parents/1
# DELETE /parents/1.json
def destroy
#parent.destroy
respond_to do |format|
format.html { redirect_to parents_url, notice: 'Parent was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_parent
#parent = Parent.find(params[:id])
end
def parent_params
params.require(:parent).permit(:name, childs_attributes: [:name])
end
end
parent form.html.erb
<%= form_for(#parent) do |f| %>
<% if #parent.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#parent.errors.count, "error") %> prohibited this parent from being saved:</h2>
<ul>
<% #parent.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label 'Parent name' %><br>
<%= f.text_field :name %>
</div>
<%= f.fields_for :child do |c| %>
<div class="field">
<%= c.label 'Child Name' %><br>
<%= c.text_field :name %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
The parent is getting created but the child is not. The child table has parent_id for associating both models.
Thanks in advance
I believe the plural of child is not childs, but children, and Rails knows this. You need to change your has_many association accordingly.
EDIT: As #pavan pointed out, change all the occurences in your code, not only the association.

Rails nested form error: param is missing or the value is empty

I am building an app that allows a user to create a contest. Each contest has many questions and each contests has many entries. Each entry has many answers and each question has many answers. Here are my models:
class Answer < ActiveRecord::Base
belongs_to :entry
belongs_to :question
end
class Contest < ActiveRecord::Base
has_many :entries
has_many :questions
end
class Entry < ActiveRecord::Base
belongs_to :contest
has_many :answers
accepts_nested_attributes_for :answers, allow_destroy: true
end
class Question < ActiveRecord::Base
has_many :answers
belongs_to :contest
end
Everything works except for when I try to create an entry. I get a "param is missing or the value is empty: entry" error. Here is my controller:
class EntriesController < ApplicationController
before_action :set_entry, only: [:show, :edit, :update, :destroy]
before_action :set_contest
# GET /entries
# GET /entries.json
def index
#entries = Entry.all
end
# GET /entries/1
# GET /entries/1.json
def show
end
# GET /entries/new
def new
#entry = Entry.new
end
# GET /entries/1/edit
def edit
end
# POST /entries
# POST /entries.json
def create
#entry = Entry.new(entry_params)
#entry.contest = #contest
respond_to do |format|
if #entry.save
format.html { redirect_to #entry, notice: 'Entry was successfully created.' }
format.json { render :show, status: :created, location: #entry }
else
format.html { render :new }
format.json { render json: #entry.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /entries/1
# PATCH/PUT /entries/1.json
def update
respond_to do |format|
if #entry.update(entry_params)
format.html { redirect_to #entry, notice: 'Entry was successfully updated.' }
format.json { render :show, status: :ok, location: #entry }
else
format.html { render :edit }
format.json { render json: #entry.errors, status: :unprocessable_entity }
end
end
end
# DELETE /entries/1
# DELETE /entries/1.json
def destroy
#entry.destroy
respond_to do |format|
format.html { redirect_to entries_url, notice: 'Entry was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_entry
#entry = Entry.find(params[:id])
end
def set_contest
#contest = Contest.find(params[:contest_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def entry_params
params.require(:entry).permit(:contest_id, answers_attributes: [:id, :content, :entry_id, :question_id, :_destroy])
end
end
And here is my entry form:
<%= simple_form_for([#contest, #entry]) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<h3>Questions</h3>
<%= simple_fields_for :answers do |ff| %>
<% #contest.questions.each do |question| %>
<h4><%= question.content %></h4>
<%= ff.input :content, input_html: {class: 'form-control'} %>
<% end %>
<% end %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
I am still working on the logic but am perplexed as to why the entry form is giving me this error. Any help would be appreciated!
UPDATE
In the Rails Guide example they show the new action as:
def new
#person = Person.new
2.times { #person.addresses.build}
end
Do I need to build the answer objects in my new action? I'm not sure... I tried it but it didn't work. I feel like that can't be the problem though as the error is coming from the entry_params method
You should be adding this line to your new action.
#entry.answers.build
And change this line
<%= simple_fields_for :answers do |ff| %>
to
<%= f.simple_fields_for :answers do |ff| %>

acts_as_taggable issue - Everything looks almost fine

I have just followed step by step this other question, but my app is still giving me some errors regarding tagging (rails 4)
Error that Im experiencing is: Desktop/hack/app/controllers/jacks_controller.rb:85: syntax error, unexpected end-of-input, expecting keyword_end end ^
I have already re-intended as suggested in the chat, but nothing changed.
Code for reference
I have no associations between my models, (in the link that I have referred, there are associations)
jack form
<%= form_for(#jack) do |f| %>
<% if #jack.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#jack.errors.count, "error") %> prohibited this jack from being saved: </h2>
<ul>
<% #jack.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :tag_list, "Tags (separated by comma)" %><br>
<%= f.text_field :tag_list %>
</div>
<div class="field">
<%= f.label :picture %><br>
<%= f.text_field :picture %>
</div>
<div class="actions">
<%= f.submit %>
jack.rb
class Jack < ActiveRecord::Base
acts_as_taggable_on :tags
end
Routes
Rails.application.routes.draw do
get 'tagged/index'
root :to => redirect('/jacks')
get 'about' => "about#info"
get 'submit' => "jacks#create"
resources :jacks
match 'tagged', to: 'jacks#tagged', :as => 'tagged', via: 'get'
resources :users
jack active helper
module JacksHelper
include ActsAsTaggableOn::TagsHelper
end
And controller
class JacksController < ApplicationController
before_action :set_jack, only: [:show, :edit, :update, :destroy]
# GET /jacks
# GET /jacks.json
def index
if params [:tag]
#jacks = Jack.tagged_with(params[:tag])
else
#jacks = Jack.all
end
# GET /jacks/1
# GET /jacks/1.json
def show
end
# GET /jacks/new
def new
#jack = Jack.new
end
# GET /jacks/1/edit
def edit
end
# POST /jacks
# POST /jacks.json
def create
#jack = Jack.new(jack_params)
respond_to do |format|
if #jack.save
format.html { redirect_to #jack, notice: 'Jack was successfully created.' }
format.json { render :show, status: :created, location: #jack }
else
format.html { render :new }
format.json { render json: #jack.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /jacks/1
# PATCH/PUT /jacks/1.json
def update
respond_to do |format|
if #jack.update(jack_params)
format.html { redirect_to #jack, notice: 'Jack was successfully updated.' }
format.json { render :show, status: :ok, location: #jack }
else
format.html { render :edit }
format.json { render json: #jack.errors, status: :unprocessable_entity }
end
end
end
# DELETE /jacks/1
# DELETE /jacks/1.json
def destroy
#jack.destroy
respond_to do |format|
format.html { redirect_to jacks_url, notice: 'Jack was successfully destroyed.' }
format.json { head :no_content }
end
end
def tagged
if params[:tag].present?
#jacks = Jack.tagged_with(params[:tag])
else
#jacks = Jack.postall
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_jack
#jack = Jack.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def jack_params
params.require(:jack).permit(:title, :description, :picture, :tag_list)
end
end
index method is missing an 'end'
def index
if params[:tag]
#jacks = Jack.tagged_with(params[:tag])
else
#jacks = Jack.all
end
end

Resources