I am trying to make a association between Printlist and Product, Template and Paper Type, but I'm getting an error. When I submit the new form, it redirects to the index route, but ramains at the same new page and do not save the info to the DB.
Controller:
class PrintlistsController < ApplicationController
before_action :set_printlist, only: [:show, :edit, :update, :destroy]
def index
#printlists = Printlist.all
#preco = calcular_preco(Printlist.count(:id),Printlist.count(:id),Printlist.count(:id),Printlist.count(:id),Printlist.count(:id),Printlist.count(:id),Printlist.count(:id))
end
def show
end
def new
#printlist = Printlist.new
end
def edit
end
def create
#binding.pry
#product = Product.where('codref': product_params['codref'])
#template = Poster.find(layout_params['id'])
#size = Cartaze.find(cartaz_params['id'])
#if product.nil?
# product = Product.new
# product.codref = product_params['codref']
# product.title = product_params['title']
# product.tipo = product_params['tipo']
# product.size = product_params['size']
# product.save
#end
#printlist = Printlist.new(printlist_params)
##printlist.product = product
##printlist.template = template
##printlist.size = size
respond_to do |format|
if #printlist.save
format.html { redirect_to printlists_path , notice: 'Impression was successfully created.' }
format.json { render :show, status: :created, location: #printlist }
else
format.html{ render :new }
format.json{ render json: #printlistst.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #printlist.update(printlist_params)
format.html { render action: "edit" }
format.json { render :show, status: :ok, location: #printlist }
else
format.html { render :edit }
format.json { render json: #printlist.errors, status: :unprocessable_entity }
end
end
end
def destroy
#printlist = Printlist.find(params[:id])
#printlist.destroy
respond_to do |format|
format.html { redirect_to(Printlists_path) }
format.xml { head :ok }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_printlist
#printlist = Printlist.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def printlist_params
params.require(:printlist).permit(:product_id, :poster_id, :cartaze_id)
end
def calcular_preco(na0, na1, na2, na3, na4, na5, na6)
#formulando preco
#precos = {a0: 1, a1: 2, a2: 3, a3: 4, a4: 5, a5: 6, a6: 7}
#cartaz = Cartaze.all
pr = HashWithIndifferentAccess.new(#cartaz.map{ |c| [c.size.to_s,c.price.to_f] }.to_h)
#precos = HashWithIndifferentAccess.new({a0: 1, a1: 2, a2: 3, a3: 4, a4: 5, a5: 6, a6: 7})
#preco_total = (na0 * pr[:A0]) + (na1 * pr[:A1]) + (na2 * pr[:A2]) + (na3 * pr[:A3]) + (na4 * pr[:A4]) + (na5 * pr[:A5]) + (na6 * pr[:A6])
end
#def product_params
#params.require(:product_id).permit(:product_id)
#end
#def poster_params
# params.require(:poster).permit(:id)
#end
#def cartaze_params
# params.require(:cartaze).permit(:id, :size)
#end
end
new.html.erb.rb form:
<%= render "/partials/sidebar" %>
<div class="conteudo-dash">
<div class="linha-dash">
<div class="panel panel-defaul col-md-6">
<div class="panel-body">
<h2>Cadastro de Cartaz</h2>
<%= form_for(#printlist, url: printlists_path) do |f|%>
<%= f.collection_select(:product_id, Product.all, :id, :title,{}, {class: "form-control col-md-3"}) %>
<%= f.collection_select(:poster_id, Poster.all, :id, :name,{},{class: "form-control"}) %>
<%= f.collection_select(:cartaze_id, Cartaze.all, :id, :size, {},{class: "form-control"}) %><br>
<%= f.submit "Salvar Produto", class: "btn btn-success" %>
<% end %>
</div>
</div>
</div>
</div>
</div>
printlist.rb model:
class Printlist < ApplicationRecord
include ActiveModel::ForbiddenAttributesProtection
belongs_to :posters
belongs_to :cartazes
belongs_to :products
end
schema.rb:
ActiveRecord::Schema.define(version: 20170523202905) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "cartazes", force: :cascade do |t|
t.string "product"
t.decimal "price", precision: 7, scale: 2
t.string "tipo"
t.string "size"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "dashboards", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "products_id"
t.integer "posters_id"
t.integer "cartazes_id"
t.index ["cartazes_id"], name: "index_dashboards_on_cartazes_id", using: :btree
t.index ["posters_id"], name: "index_dashboards_on_posters_id", using: :btree
t.index ["products_id"], name: "index_dashboards_on_products_id", using: :btree
end
create_table "dashboards_posters", id: false, force: :cascade do |t|
t.integer "dashboard_id", null: false
t.integer "poster_id", null: false
t.index ["dashboard_id", "poster_id"], name: "index_dashboards_posters_on_dashboard_id_and_poster_id", using: :btree
end
create_table "posters", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "printlists", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "product_id"
t.integer "poster_id"
t.integer "cartaze_id"
t.index ["cartaze_id"], name: "index_printlists_on_cartaze_id", using: :btree
t.index ["poster_id"], name: "index_printlists_on_poster_id", using: :btree
t.index ["product_id"], name: "index_printlists_on_product_id", using: :btree
end
create_table "products", force: :cascade do |t|
t.string "title"
t.decimal "price"
t.string "tipo"
t.string "size"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.decimal "preco_promo", precision: 7, scale: 2
t.string "codref"
end
create_table "servicos", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end
add_foreign_key "dashboards", "cartazes", column: "cartazes_id"
add_foreign_key "dashboards", "posters", column: "posters_id"
add_foreign_key "dashboards", "products", column: "products_id"
end
EDIT
routes.rb
Rails.application.routes.draw do
get 'notification/create'
resources :products
devise_for :users
root 'home#index'
# user_root_path 'dashboard#index' # DEPOIS DO CLIENTE ESTAR LOGADO redireciona pra dashboard
post 'pgtcheckout/create'
post 'notification', to: 'notification#create'
resources :users
get 'pgtcheckout' => 'pgtcheckout#index'
get 'pgtcheckout/new' => 'pgtcheckout#new'
resources :dashboards
resources :product
resources :posters
resources :printlists
Console Output
Started POST "/printlists" for ::1 at 2017-05-29 13:53:04 -0300
Processing by PrintlistsController#create as HTML
Parameters: {"utf8"=>"V", "authenticity_token"=>"KrKq5k71/exf2nnw56F43IbbZz7CRdjnsvTSulSNAM9Uj8lPB8tnQ9BfDifeXlMLVTNqIs6/T1dSeIS5zeph
sQ==", "printlist"=>{"product_id"=>"7", "poster_id"=>"4", "cartaze_id"=>"3"}, "commit"=>"Salvar Produto"}
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1
]]
(0.0ms) BEGIN
(0.0ms) ROLLBACK
Rendering printlists/new.html.erb within layouts/application
Rendered partials/_sidebar.html.erb (12.0ms)
Product Load (1.0ms) SELECT "products".* FROM "products"
Poster Load (0.0ms) SELECT "posters".* FROM "posters"
Cartaze Load (0.0ms) SELECT "cartazes".* FROM "cartazes"
Rendered printlists/new.html.erb within layouts/application (52.0ms)
Completed 200 OK in 1117ms (Views: 1106.2ms | ActiveRecord: 2.0ms)
Debug Output:
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
utf8: "β"
authenticity_token: KrKq5k71/exf2nnw56F43IbbZz7CRdjnsvTSulSNAM9Uj8lPB8tnQ9BfDifeXlMLVTNqIs6/T1dSeIS5zephsQ==
printlist: !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
product_id: '1'
poster_id: '3'
cartaze_id: '3'
permitted: false
commit: Salvar Produto
The new Printlist object is failing a validation when executing #printlist.save on create action; that's why you get a (0.0ms) ROLLBACK in your logs.
So, #printlist.save returns false and executes format.html { render :new }; as instructed in create action:
if #printlist.save
format.html { redirect_to printlists_path , notice: 'Impression was successfully created.' }
format.json { render :show, status: :created, location: #printlist }
else
format.html{ render :new }
format.json{ render json: #printlistst.errors, status: :unprocessable_entity }
end
To spot the error, use save! instad of save (this is only temporary), that will raise an exception describing why the object is not valid, and thus not saving.
With save! in place, now you will get an exception (instead of a ROLLBACK) in your logs with the error message.
Once you spot why your validation fails, you can fix it; and don't forget to change back save! to save.
Related
I been working on a sort of gun display social media website thing but I ran into a problem where after I added the user_id to the gun model the save view will go to the create controller but wont save when the if save line (in the controller) is suppose to run. It worked in rails console but not by the controller.
schema
ActiveRecord::Schema.define(version: 2021_02_06_222048) do
create_table "guns", force: :cascade do |t|
t.integer "year"
t.string "model"
t.string "condition"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "user_id", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
model
class Gun < ApplicationRecord belongs_to :users
view
<h1>Create your Gun here</h1>
<form method = "post" action = <%=gun_index_url%>>
<label for = "gun_model">Gun model</label>
<input
type = "text"
name = "gun[model]"
id = "gun_model">
<label for = "gun_condtion">Condtion</label>
<input
type = "text"
name = "gun[condition]"
id = "gun_condtion">
<label for = year>Year manerfacterd</label>
<input
type = "number"
value = "2000"
name = "gun[year]"
id = "gun_year">
<input
type = "hidden"
value = "<%=current_user.id%>"
name = "gun[user_id]"
id = "user_id">
<input
type = "hidden"
value = "<%=form_authenticity_token%>"
name = "authenticity_token">
<input type="submit" value="sumbit">
</form>
Controller model
class GunController < ApplicationController
before_action :authenticate_user!, only: [:new]
def index
#guns = Gun.all
render :index
end
def new
#gun = Gun.new
render :new
end
def edit
#gun = Gun.find(params[:id])
render :edit
end
def create
#gun = Gun.new(gun_params)
if #gun.save
redirect_to gun_url(#gun)
else
redirect_to new_gun_url
raise ArgumentError.new
end
end
def show
#gun = Gun.find(params[:id])
render :show
end
def update
#gun = Gun.find(params[:id])
if #gun.update(gun_params)
redirect_to gun_url(#gun)
else
render :edit
raise ArgumentError.new
end
end
def destroy
#gun = Gun.find(params[:id])
#gun.destroy
redirect_to gun_index_url
end
private
def gun_params
params.require(:gun).permit(:condition ,:year ,:model, :user_id)
end
I found out that the
belongs_to :users
was not supost to be pular and should have been
belongs_to :user
typically when a model wont save its a validation error. use the bang (!) methods to figure out what actually cases it..
so, instead of save use save! or instead of update, update!
I'm building an API for an app where a user can make appointments with a doctor.
Everything is working just fine but it's returning 204 - No content when I try to post a new appointment in Postman.
My schema:
create_table "appointments", force: :cascade do |t|
t.date "date"
t.time "time"
t.bigint "user_id"
t.bigint "doctor_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["doctor_id"], name: "index_appointments_on_doctor_id"
t.index ["user_id"], name: "index_appointments_on_user_id"
end
create_table "doctors", force: :cascade do |t|
t.string "name"
t.string "speciality"
t.integer "years_of_experience"
t.integer "likes"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email"
t.string "password_digest"
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_foreign_key "appointments", "doctors"
add_foreign_key "appointments", "users"
end
My appointments controller:
class Api::V1::AppointmentsController < ApplicationController
include CurrentUserConcern
def index
#appointments = Appointment.all
render json: #appointments
end
def create
if #current_user
#appointment = #current_user.appointments.build(appointment_params)
if #appointment.save
render json: #appointment
else
render json: { status: 401 }
end
end
end
private
def appointment_params
params.require(:appointment).permit(:time, :date, #current_user.id, :doctor_id)
end
end
First of all there's not need of sending #current_user.id in appointment_params as user_id will be assigned automatically when this line #appointment = #current_user.appointments.build(appointment_params) execute.
Coming to your issue make sure you are sending a POST request and "body" data in the correct JSON format from PostMan. As per your method appointment_params the request body should look like this
{
appointment: {
time: "",
date: "",
doctor_id:
}
}
I have 2 models: Customer and Sale
class Sale < ApplicationRecord
belongs_to :customer, inverse_of: :sales
accepts_nested_attributes_for :customer
end
class Customer < ApplicationRecord
has_many :sales, inverse_of: :customer
end
In SALE controller i have a form with CUSTOMER'S values
To create new sale i don't have any problem, but when i try update, the error "unknown attribute 'valor_oferta' for Customer" appears
Sale Controller
class SalesController < ApplicationController
before_action :authenticate_user!
def new
#sale = Sale.new
#sale.build_customer
end
def create
#sale = Sale.new(proposta_params)
respond_to do |format|
if #sale.save
format.html { redirect_to dashboard_path, notice: 'Proposta criada com sucesso.' }
else
format.html { render :new }
#sale.errors.each do |erro|
puts erro
end
end
end
end
def edit
#sale = Sale.find(params[:id])
#sale.customer
end
def update
#sale = Sale.find(params[:id])
respond_to do |format|
if #sale.customer.update(proposta_params)
format.html { redirect_to dashboard_path, notice: 'Proposta alterada com sucesso.' }
else
format.html { render :edit }
#sale.errors.each do |erro|
puts erro
end
end
end
end
private
def proposta_params
params.require(:sale).permit(:valor_oferta, :grupo_promocao, :codigo_oferta, :modo_pagamento, :vencimento, :banco, :agencia, :conta, :isento, :valor, :data_envio_qualidade, :data_agendamento_qualidade, :janela_agendamento, :data_instalacao_qualidade,:tv_id, :phone_id, :internet_id, :equipamentos, :cep, :rua, :numero, :complemento, :bairro, :cidade, :uf, :ponto_de_referencia, :obs, customer_attributes: [:name, :cpf_pf, :nascimento_pf, :nome_mae_pf, :nome_mae_pf, :cnpj_pj, :fundacao_pj, :telefone1, :telefone2, :telefone3, :email, :juridica])
end
end
I already tried use only
if #sale.update(proposta_params)
but in this case, another Customer is created and not updated
I use Rails 5
#################EDIT
db/schema.rb
create_table "sales", force: :cascade do |t|
t.integer "lead_id"
t.string "solicitante"
t.integer "protocolo"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "tv_id"
t.integer "phone_id"
t.integer "internet_id"
t.string "solicitante_pf"
t.string "valor_oferta"
t.string "grupo_promocao"
t.string "codigo_oferta"
t.string "vencimento"
t.boolean "isento"
t.string "valor"
t.string "data_envio_qualidade"
t.string "data_agendamento_qualidade"
t.string "janela_agendamento"
t.string "data_instalacao_qualidade"
t.integer "customer_id"
t.string "agencia"
t.string "conta"
t.string "banco"
t.string "modo_pagamento"
t.integer "equipamentos"
t.string "cep"
t.string "rua"
t.string "numero"
t.string "complemento"
t.string "bairro"
t.string "cidade"
t.string "uf"
t.string "ponto_de_referencia"
t.text "obs"
t.integer "user_id"
t.integer "user_qualidade_id"
t.integer "status_sale_id"
t.index ["customer_id"], name: "index_sales_on_customer_id", using: :btree
t.index ["internet_id"], name: "index_sales_on_internet_id", using: :btree
t.index ["lead_id"], name: "index_sales_on_lead_id", using: :btree
t.index ["phone_id"], name: "index_sales_on_phone_id", using: :btree
t.index ["status_sale_id"], name: "index_sales_on_status_sale_id", using: :btree
t.index ["tv_id"], name: "index_sales_on_tv_id", using: :btree
t.index ["user_id"], name: "index_sales_on_user_id", using: :btree
end
I'm creating a clothing store. I have Categories that have Sizes. A womens shirt (Category) might have XS, S, M, Large. A mens shirt can have XS, S, M, L. Shoes can have 4-16 and so on.
I have created a has_many through: association that connects the Category table with Sizes table by a Cateogry_Sizes table.
When an admin creates a Category, they should select all the Sizes that the Category will need.
How can I select the Sizes in the below view?
The current code is incorrect. In the console, when I go to category.sizes, I just get an empty array.
View:
<div class="container">
<div class=βrowβ>
<div class="col-md-6 col-md-offset-3">
<div class="panel panel-primary">
<div class="panel-body">
<%= simple_form_for(#category) do |f| %>
<div class="form-inputs">
<%= f.input :name %>
<%= f.select(:sizes, Size.all.map {|s| [s.title, s.id]}, :multiple => true) %>
<%= f.collection_select :parent_id, Category.order(:name), :id, :name, {prompt: "Select Parrent ID If Applicable"},include_blank: true %>
<div class="form-actions"><%= f.button :submit %></div>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
Category model:
class Category < ActiveRecord::Base
has_ancestry
has_many :items
validates :name, presence: true, length: { maximum: 20 }
has_many :category_sizes
has_many :sizes, through: :category_sizes
end
Size model:
class Size < ActiveRecord::Base
validates :title, presence: true, length: { maximum: 15 }
validates :title, uniqueness: true
has_many :category_sizes
has_many :categories, through: :category_sizes
end
Category_size model:
class CategorySize < ActiveRecord::Base
belongs_to :category
belongs_to :size
end
Schema:
ActiveRecord::Schema.define(version: 20150920013947) do
create_table "categories", force: :cascade do |t|
t.string "name"
t.string "ancestry"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "categories", ["ancestry"], name: "index_categories_on_ancestry"
create_table "category_sizes", force: :cascade do |t|
t.integer "category_id"
t.integer "size_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "category_sizes", ["category_id"], name: "index_category_sizes_on_category_id"
add_index "category_sizes", ["size_id"], name: "index_category_sizes_on_size_id"
create_table "items", force: :cascade do |t|
t.string "title"
t.decimal "price"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.integer "category_id"
end
add_index "items", ["user_id", "created_at"], name: "index_items_on_user_id_and_created_at"
add_index "items", ["user_id"], name: "index_items_on_user_id"
create_table "sizes", force: :cascade do |t|
t.text "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "taggings", force: :cascade do |t|
t.integer "tag_id"
t.integer "taggable_id"
t.string "taggable_type"
t.integer "tagger_id"
t.string "tagger_type"
t.string "context", limit: 128
t.datetime "created_at"
end
add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true
add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context"
create_table "tags", force: :cascade do |t|
t.string "name"
t.integer "taggings_count", default: 0
end
add_index "tags", ["name"], name: "index_tags_on_name", unique: true
create_table "users", force: :cascade do |t|
t.string "username"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.string "remember_digest"
t.boolean "admin", default: false
t.string "activation_digest"
t.boolean "activated", default: false
t.datetime "activated_at"
t.string "reset_digest"
t.string ">"
t.datetime "reset_sent_at"
t.string "avatar_file_name"
t.string "avatar_content_type"
t.integer "avatar_file_size"
t.datetime "avatar_updated_at"
t.text "description"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
end
Controller:
class CategoriesController < ApplicationController
before_action :set_category, only: [:show]
before_action :admin_user, only: [:destroy, :index, :edit, :show]
def index
#categories = Category.all
end
def show
#tags = Item.where(category_id: #category.id).tag_counts_on(:tags)
if params[:tag]
#items = Item.tagged_with(params[:tag])
else
#items = Item.where(category_id: #category.id).order("created_at DESC")
end
end
def new
#category = Category.new
end
def edit
#category = Category.find(params[:id])
end
def create
#category = Category.new(category_params)
if #category.save
redirect_to #category
flash[:success] = "You have created a new category"
else
flash[:danger] = "Your category didn't save"
render "new"
end
end
def update
#Cateogry = Category.find(params[:id])
if #Cateogry.update(category_params)
redirect_to #Cateogry
flash[:success] = 'Category was successfully updated.'
else
render "edit"
end
end
def destroy
Category.find(params[:id]).destroy
flash[:success] = "Category deleted"
redirect_to categories_path
end
private
def set_category
#category = Category.find(params[:id])
end
def category_params
params.require(:category).permit(:name, :parent_id)
end
# Confirms an admin user.
def admin_user
redirect_to(root_url) unless current_user.try(:admin?)
end
end
Here is what happens when in console:
2.1.2 :026 > c = Category.last
Category Load (0.3ms) SELECT "categories".* FROM "categories" ORDER BY "categories"."id" DESC LIMIT 1
=> #<Category id: 57, name: "Test20", ancestry: "20", created_at: "2015-09-23 12:35:14", updated_at: "2015-09-23 12:35:14">
2.1.2 :027 > c.sizes
Size Load (0.2ms) SELECT "sizes".* FROM "sizes" INNER JOIN "category_sizes" ON "sizes"."id" = "category_sizes"."size_id" WHERE "category_sizes"."category_id" = ? [["category_id", 57]]
Here is what happens on form submit in server log:
Started POST "/categories" for ::1 at 2015-09-23 22:37:28 +1000
Processing by CategoriesController#create as HTML
Parameters: {"utf8"=>"β", "authenticity_token"=>"4pMZ9PUr5yTSCNRiQeATljZsOIDeQCwhQPy9djEbAmejntpb8/DkK20JrMUeZkStsB5UU6YhbtExGwDKs7tT2Q==", "category"=>{"name"=>"test21", "sizes"=>"6", "parent_id"=>"20"}, "commit"=>"Create Category"}
Unpermitted parameter: sizes
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE "categories"."id" = ? LIMIT 1 [["id", 20]]
(0.1ms) begin transaction
SQL (0.3ms) INSERT INTO "categories" ("name", "ancestry", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "test21"], ["ancestry", "20"], ["created_at", "2015-09-23 12:37:28.927360"], ["updated_at", "2015-09-23 12:37:28.927360"]]
(1.0ms) commit transaction
Redirected to http://localhost:3000/categories/58
Completed 302 Found in 5ms (ActiveRecord: 1.5ms)
Started GET "/categories/58" for ::1 at 2015-09-23 22:37:28 +1000
Processing by CategoriesController#show as HTML
Parameters: {"id"=>"58"}
You need to allow the sizes in the params of the controller like this:
def category_params
params.require(:category).permit(:name, :parent_id, size_ids: [])
end
In your form you should probably change:
<%= f.select(:sizes, Size.all.map {|s| [s.title, s.id]}, :multiple => true) %>
to
<%= f.association :sizes %>
Simple form should then do the magic. See also: https://github.com/plataformatec/simple_form#associations for more information.
As an aside, I felt it apt to highlight that you may be able to use has_and_belongs_to_many to make this work in its current form. It works very similarly to has_many :through except it doesn't have a join model:
#app/models/category.rb
class Category < ActiveRecord::Base
has_and_belongs_to_many :sizes
end
#app/models/size.rb
class Size < ActiveRecord::Base
has_and_belongs_to_many :categories
end
This will mean you'll have to drop your category_sizes table and replace it with categories_sizes with category_id | size_id columns:
This is only recommended if you don't want to include any further information in your join model. For example, if you wanted to include stock levels or something, the join model of has_many :through would be vital; not as you have it now.
It will also allow you to call:
#category = Category.find params[:id]
#category.sizes #-> collection of sizes for category.
--
Form
HABTM also would make the form much simpler:
<%= simple_form_for(#category) do |f| %>
<%= f.input :name %>
<%= f.collection_select :sizes, Size.all, :id, :name, { multiple: true } %>
<%= f.collection_select :parent_id, Category.order(:name), :id, :name, {prompt: "Select Parent ID If Applicable"},include_blank: true %>
<%= f.submit %>
<% end %>
#app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
def create
#category = Category.new category_params
end
private
def category_params
params.require(:category).permit(:etc, :etc, :sizes)
end
end
I am not sure why my query works on localhost but is failing on the server.
This happens when i try to create a quiz which routes to QuizzesController#new
# GET /quizzes/new
def new
#quiz = current_user.quizzes.new
end
This is the query:
SELECT COUNT(*) FROM "questions" INNER JOIN "question_categories" ON "question_categories"."question_id" = "questions"."id" WHERE "questions"."deleted_at" IS NULL AND (`question_categories`.`category_id` IN (87,1))
(1.0ms) ROLLBACK
Completed 500 Internal Server Error in 58ms (ActiveRecord: 13.4ms)
And i got an error as such.
ActiveRecord::StatementInvalid (PG::SyntaxError: ERROR: syntax error at or near "." LINE 1: ...s"."deleted_at" IS NULL AND (`question_categories`.`category...
quiz.rb
before creating i would run build_parts which should randomly grab questions and place them into quizzes.
class Quiz < ActiveRecord::Base
belongs_to :user
belongs_to :subject
has_many :quiz_categories
has_many :categories, through: :quiz_categories
has_many :quiz_parts
accepts_nested_attributes_for :categories
accepts_nested_attributes_for :quiz_parts
validates :user, :subject, :number_of_questions, presence: true
validates :number_of_questions, numericality: { only_integer: true, greater_than_or_equal_to: 1 }
before_create :build_parts
before_save :set_completed_at, if: -> { completeness == 100.00 }
def completeness
answerable_quiz_parts = 0
quiz_parts.each do |q_part|
answerable_quiz_parts += 1 if q_part.answerable.answers.present?
end
quiz_parts.joins(:choice).count.to_f * 100 / answerable_quiz_parts
end
def score
quiz_parts.joins(:choice).where('choices.correct = ?', true).count { |qp| qp.choice.correct? }
end
private
# select random questions
def build_parts
category_ids = self.categories.map(&:id)
question_pool = Question.joins(:question_categories).where('`question_categories`.`category_id` IN (?)', category_ids)
#self.number_of_questions = [number_of_questions, question_pool.size].min
puts question_pool.size
if number_of_questions > question_pool.size
errors.add(:number_of_questions, 'is too high. Please select a lower question count or increase category selections')
return false
end
number_of_questions.times do |i|
question_pool.inspect
self.quiz_parts << question_pool[i].quiz_parts.new
question_pool[i].question_parts.each do |question_part|
self.quiz_parts << question_part.quiz_parts.new
end
end
end
def set_completed_at
self.completed_at = Time.zone.now
end
end
quizzes_controller.rb
class QuizzesController < ApplicationController
before_action :authenticate_user!
before_action :set_quiz, only: [:show, :edit, :update, :destroy]
# GET /quizzes
# GET /quizzes.json
def index
#quizzes = current_user.quizzes.order(created_at: :desc)
end
# GET /quizzes/1
# GET /quizzes/1.json
def show
end
# GET /quizzes/new
def new
#quiz = current_user.quizzes.new
end
# GET /quizzes/1/edit
def edit
end
# POST /quizzes
# POST /quizzes.json
def create
#quiz = current_user.quizzes.new(quiz_create_params)
respond_to do |format|
if #quiz.save
format.html { redirect_to edit_quiz_path(#quiz), notice: 'Quiz was successfully created.' }
format.json { render :show, status: :created, location: #quiz }
else
format.html { render :new }
format.json { render json: #quiz.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /quizzes/1
# PATCH/PUT /quizzes/1.json
def update
respond_to do |format|
if #quiz.update(quiz_update_params)
format.html { redirect_to #quiz, notice: 'Quiz was successfully updated.' }
format.json { render :show, status: :ok, location: #quiz }
else
format.html { render :edit }
format.json { render json: #quiz.errors, status: :unprocessable_entity }
end
end
end
# DELETE /quizzes/1
# DELETE /quizzes/1.json
def destroy
#quiz.destroy
respond_to do |format|
format.html { redirect_to quizzes_url, notice: 'Quiz was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_quiz
#quiz = current_user.quizzes.find(params[:id])
end
# For quiz setup
def quiz_create_params
params.require(:quiz).permit(:subject_id, :number_of_questions, category_ids: [])
end
# For quiz answering
def quiz_update_params
params.require(:quiz).permit(quiz_parts_attributes: [:id, choice_attributes: [:id, :content, :answer_id, :_destroy]])
end
end
schema.rb:
ActiveRecord::Schema.define(version: 20150726180000) do
create_table "admins", force: :cascade do |t|
t.string "email"
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "admins", ["confirmation_token"], name: "index_admins_on_confirmation_token", unique: true
add_index "admins", ["email"], name: "index_admins_on_email", unique: true
add_index "admins", ["reset_password_token"], name: "index_admins_on_reset_password_token", unique: true
create_table "answers", force: :cascade do |t|
t.integer "number"
t.text "content"
t.boolean "correct", default: false, null: false
t.integer "answerable_id"
t.string "answerable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "answers", ["answerable_type", "answerable_id"], name: "index_answers_on_answerable_type_and_answerable_id"
create_table "categories", force: :cascade do |t|
t.string "name"
t.integer "subject_id"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "categories", ["category_id"], name: "index_categories_on_category_id"
add_index "categories", ["subject_id"], name: "index_categories_on_subject_id"
create_table "choices", force: :cascade do |t|
t.string "content"
t.integer "quiz_part_id"
t.integer "answer_id"
t.boolean "correct"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "choices", ["answer_id"], name: "index_choices_on_answer_id"
add_index "choices", ["quiz_part_id"], name: "index_choices_on_quiz_part_id"
create_table "ckeditor_assets", force: :cascade do |t|
t.string "data_file_name", null: false
t.string "data_content_type"
t.integer "data_file_size"
t.integer "assetable_id"
t.string "assetable_type", limit: 30
t.string "type", limit: 30
t.integer "width"
t.integer "height"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "ckeditor_assets", ["assetable_type", "assetable_id"], name: "idx_ckeditor_assetable"
add_index "ckeditor_assets", ["assetable_type", "type", "assetable_id"], name: "idx_ckeditor_assetable_type"
create_table "levels", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "question_categories", force: :cascade do |t|
t.integer "question_id"
t.integer "category_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "question_categories", ["category_id"], name: "index_question_categories_on_category_id"
add_index "question_categories", ["question_id"], name: "index_question_categories_on_question_id"
create_table "question_parts", force: :cascade do |t|
t.text "content"
t.string "type"
t.integer "question_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
end
add_index "question_parts", ["deleted_at"], name: "index_question_parts_on_deleted_at"
add_index "question_parts", ["question_id"], name: "index_question_parts_on_question_id"
create_table "questions", force: :cascade do |t|
t.text "content"
t.string "type"
t.integer "level_id"
t.integer "subject_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "deleted_at"
t.string "source"
end
add_index "questions", ["deleted_at"], name: "index_questions_on_deleted_at"
add_index "questions", ["level_id"], name: "index_questions_on_level_id"
add_index "questions", ["subject_id"], name: "index_questions_on_subject_id"
create_table "quiz_categories", force: :cascade do |t|
t.integer "category_id"
t.integer "quiz_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "quiz_categories", ["category_id"], name: "index_quiz_categories_on_category_id"
add_index "quiz_categories", ["quiz_id"], name: "index_quiz_categories_on_quiz_id"
create_table "quiz_parts", force: :cascade do |t|
t.integer "quiz_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "answerable_id"
t.string "answerable_type"
end
add_index "quiz_parts", ["answerable_type", "answerable_id"], name: "index_quiz_parts_on_answerable_type_and_answerable_id"
add_index "quiz_parts", ["quiz_id"], name: "index_quiz_parts_on_quiz_id"
create_table "quizzes", force: :cascade do |t|
t.integer "user_id"
t.datetime "completed_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "subject_id"
t.integer "number_of_questions"
end
add_index "quizzes", ["subject_id"], name: "index_quizzes_on_subject_id"
add_index "quizzes", ["user_id"], name: "index_quizzes_on_user_id"
create_table "subjects", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
I believe you are using wrong quotes:
SELECT COUNT(*) ....... (`question_categories`.`category_id` IN (87,1))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use " " instead of ``
Update:
Yep, I have been right in your quiz model you're using wrong quotes:
def build_parts
category_ids = self.categories.map(&:id)
question_pool = Question.joins(:question_categories).where('`question_categories`.`category_id` IN (?)', category_ids)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Fix it to:
def build_parts
category_ids = self.categories.map(&:id)
question_pool = Question.joins(:question_categories).where('"question_categories"."category_id" IN (?)', category_ids)
^^^^^^^^^^^^^^^^^^^^^