NoMethodError for relationship between models - ruby-on-rails

I am setting up a relationship between two of my models. A Patient Model and Worklist Model. My patient can belong to a worklist and a worklist can have many patients. In my form for patients I want to be able to select the worklist from a dropdown menu. I created a method in the form but its throwing an error. Here is my code:
from _form.html.erb:
<div class="field">
<%= f.label :worklist_id %>
<%= f.collection_select :worklist_id, #worklists, :id , :name %>
</div>
from patient.rb:
class Patient < ActiveRecord::Base
belongs_to :worklist
end
from worklist.rb
class Worklist < ActiveRecord::Base
has_many :patients
end
from schema.rb
create_table "patients", force: :cascade do |t|
t.string "lastname"
t.string "middlename"
t.string "firstname"
t.date "birthdate"
t.string "sex"
t.string "ethnicity"
t.string "uniqueid"
t.string "accountnumber"
t.string "medicaidid"
t.string "medicareid"
t.string "ssn"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "worklist_id"
end
And this is the error I am getting:
NoMethodError in Patients#edit
undefined method `worklist_select'
Here is the PatientController:
class PatientsController < ApplicationController
before_action :set_patient, only: [:show, :edit, :update, :destroy]
# GET /patients
# GET /patients.json
def index
#patients = Patient.all
end
# GET /patients/1
# GET /patients/1.json
def show
end
# GET /patients/new
def new
#patient = Patient.new
end
# POST /patients
# POST /patients.json
def create
#patient = Patient.new(patient_params)
#worklists = Worklist.all
respond_to do |format|
if #patient.save
format.html { redirect_to #patient, notice: 'Patient was successfully created.' }
format.json { render :show, status: :created, location: #patient }
else
format.html { render :new }
format.json { render json: #patient.errors, status: :unprocessable_entity }
end
end
end
# GET /patients/1/edit
def edit
end
# PATCH/PUT /patients/1
# PATCH/PUT /patients/1.json
def update
respond_to do |format|
if #patient.update(patient_params)
format.html { redirect_to #patient, notice: 'Patient was successfully updated.' }
format.json { render :show, status: :ok, location: #patient }
else
format.html { render :edit }
format.json { render json: #patient.errors, status: :unprocessable_entity }
end
end
end
# DELETE /patients/1
# DELETE /patients/1.json
def destroy
#patient.destroy
respond_to do |format|
format.html { redirect_to patients_url, notice: 'Patient was successfully destroyed.' }
format.json { head :no_content }
end
end
def import
Patient.import(params[:file])
redirect_to patients_path, notice: "Patients Added Successfully"
end
private
# Use callbacks to share common setup or constraints between actions.
def set_patient
#patient = Patient.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def patient_params
params.require(:patient).permit(:lastname, :middlename, :firstname, :birthdate, :sex, :ethnicity, :uniqueid, :accountnumber, :medicaidid, :medicareid, :ssn, :worklist_id)
end
end

Worklist.all in the view is a problem. The view talking to the db directly is never good. That is the Controller's (or a Service's) job.
In your controller, you would want something like: #worklists = Worklist.all, then use #worklists in the view.
This is just a start though. Can you post your controller so we can help further?
UPDATE: Now we have a better idea of where this is going. Lets do this:
So in your PatientsController, you would want this in your create method:
#worklists = Worklist.all
Then in your _form.html.erb (from the patient folder NOT the Worklist folder), you would want:
<%= f.label :worklist_id %>
<%= f.collection_select :worklist_id, #worklists, :id , :name %>

I think if you just change this:
<%= worklist_select( :patient, :worklist_id, Worklist.all, :id, :name, {}, { :multiple => false } ) %>
To something more like this:
<%= f.select( :worklist_id, Worklist.all, :id, :name, {}, { :multiple => false } ) %>
You might get what you want.

Related

RAILS - ActiveModel::MissingAttributeError - Possible issue with how array is being stored?

I'm getting a missing attribute error when trying to automatically create a InvoiceAppCollection when an Invoice is created.
This is the error that I'm getting:
ActiveModel::MissingAttributeError in InvoicesController#create
can't write unknown attribute app_collection_id
From what I've looked up when other people have this issue it has to do with the relationships between the models, but I'm pretty sure that I have the models communicating to each other properly.
The function I wrote to create the invoice app collection is in the invoice controller
def create_invoice_app_collection
InvoiceAppCollection.create(
po_number: #invoice.po_number,
app_collection: #invoice.app_collection
)
end
Here are my models and controllers. I also have the select box where the app_collections are being selected at the bottom.
Here are the Models
class AppCollection < ApplicationRecord
belongs_to :company
acts_as_tenant(:company)
has_many :invoice_app_collections
has_many :invoices, through: :invoice_app_collections
validates :name, uniqueness: true
end
class Invoice < ApplicationRecord
belongs_to :company
acts_as_tenant(:company)
has_many :invoice_app_collections
has_many :app_collections, through: :invoice_app_collections
validates :expiration, on: [:create, :update, :save], :presence => true
end
class InvoiceAppCollection < ApplicationRecord
belongs_to :app_collection
belongs_to :invoice
belongs_to :company
acts_as_tenant(:company)
accepts_nested_attributes_for :app_collection
end
AppCollectionController
class AppCollectionsController < ApplicationController
before_action :set_app_collection, only: %i[ show edit update destroy ]
def index
AppCollections = app_collection.all
end
def create
#app_collection = app_collection.new(app_collection_params)
respond_to do |format|
if #app_collection.save
format.html { redirect_to app_collection_url(#app_collection), notice: "App collection was successfully created." }
format.json { render :show, status: :created, location: #app_collection }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #app_collection.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #app_collection.update(app_collection_params)
format.html { redirect_to app_collection_url(#app_collection), notice: "App collection was successfully updated." }
format.json { render :show, status: :ok, location: #app_collection }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #app_collection.errors, status: :unprocessable_entity }
end
end
end
def destroy
#app_collection.destroy
respond_to do |format|
format.html { redirect_to app_collections_url, notice: "app collection was successfully destroyed." }
format.json { head :no_content }
end
end
private
def set_app_collection
#app_collection = app_collection.find(params[:id])
end
def app_collection_params
params.require(:app_collection).permit(:app_collection_type_id, :name, :company_id)
end
end
InvoicesController
class InvoicesController < ApplicationController
before_action :set_invoice, only: %i[ show edit update destroy ]
prepend_before_action :set_tenant
after_action :create_invoice_app_collection, only: [:create, :update]
def new
#invoice_app_collection = Invoice.new
end
def create
#invoice = Invoice.new(invoice_params)
respond_to do |format|
if #invoice.save
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully created." }
format.json { render :show, status: :created, location: #invoice }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #invoice.update(invoice_params)
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully updated." }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
private
def set_invoice
#invoice = Invoice.find(params[:id])
end
def invoice_params
params.require(:invoice).permit(:company_id, :po_number, :amount, :expiration, {:app_collection_id => []} )
end
def create_invoice_app_collection
InvoiceAppCollection.create(
po_number: #invoice.po_number,
app_collection: #invoice.app_collection
)
end
end
InvoiceAppCollectionsController
class InvoiceAppCollectionsController < ApplicationController
before_action :set_invoice_app_collection, only: %i[ show edit update destroy ]
prepend_before_action :set_tenant
def new
#invoice_app_collection = InvoiceAppCollection.new
end
private
def set_invoice_app_collection
#invoice_app_collection = InvoiceAppCollection.find(params[:id])
end
def invoice_app_collection_params
params.require(:invoice_app_collection).permit(:company_id, :po_number, {:app_collection => []} )
end
end
App Collection being set in the invoice form
<div>
<%= form.label :app_collection, style: "display: block" %>
<label> Select multiple app collections by holding the command key </label>
<%= form.select :app_collection, options_for_select(app_collection.all.map {|a| [a.name, a.name]}),{include_blank: false} , class:"form-select", multiple: true %>
</div>
Schema
create_table "app_collections", charset: "latin1", force: :cascade do |t|
t.integer "app_collection_type_id"
t.string "name"
t.integer "company_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "invoice_app_collections", charset: "latin1", force: :cascade do |t|
t.integer "company_id"
t.string "po_number"
t.string "app_collection"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "invoices", charset: "latin1", force: :cascade do |t|
t.integer "company_id"
t.string "po_number"
t.decimal "amount", precision: 10
t.datetime "expiration"
t.string "app_collection"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
I believe that the issue is that the app_collection is an array that gets sent to InvoiceAppController so I set it to an array in both controllers and that hasn't fixed it. I also allowed InvoiceAppCollection to accept nested attribues for app_collection but that also isn't fixing it.
I'm not really sure how to resolve this error so any guidance would be very appreciated
Thank you!
I found a small problem, you wrote: #invoice.app_collection, but as your Invoice model is:
class Invoice < ApplicationRecord
has_many :app_collections, through: :invoice_app_collections
end
The code will look for relation belongs_to :app_collection, it required column app_collection_id in your Invoice model, which is not correct in this many-to-many between Invoice and AppCollection. Btw, I think this part {:app_collection_id => []} of invoice_params could raise error when this code Invoice.new(invoice_params) is executed
My suggestion, to update the many-to-many relation:
#invoice.app_collections = AppCollection.where(id: params[:app_collection_ids]) // maybe you will want to update the params structure
#invoice.save
This code will auto-generate correspondant InvoiceAppCollection records.

Ransack Search Error: param is missing or the value is empty: profile

I'm very new to ruby on rails so the issue I have may seem obvious from my code but not to me.
I am using the Ransack search gem in my application. I want to search a profile by 'location' but for some reason when I search I receive the following error:
ActionController::ParameterMissing in ProfilesController#create
param is missing or the value is empty: profile
def profile_params
params.require(:profile).permit(:full_name, :contact_number, :location, :makeup_type, :bio, :user_id, :image)
end
I have looked up this error and I can't seem to figure out what might be causing it. All the fields are there that need to be.
My Profiles Controller:
class ProfilesController < ApplicationController
before_action :set_profile, only: [:show, :edit, :update, :destroy]
def index
#search = Profile.search(params[:q])
#profiles = #search.result(distinct: true)
end
def show
#profile = Profile.find(params[:id])
end
def new
#profile = Profile.new
end
def create
#profile = Profile.new(profile_params)
respond_to do |format|
if #profile.save
format.html { redirect_to #profile, notice: 'Your Profile was successfully created' }
format.json { render :show, status: :created, location: #profile }
else
format.html { render :new }
format.json { render json: #profile.errors, status: :unprocessable_entry }
end
end
end
def edit
#profile = Profile.find(params[:id])
end
def update
respond_to do |format|
if #profile.update(profile_params)
format.html { redirect_to #profile, notice: 'Profile was successfully updated.' }
format.json { render :show, status: :ok, location: #profile }
else
format.html { render :edit }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
def destroy
#profile.destroy
respond_to do |format|
format.html { redirect_to profile_url, notice: 'Profile was successfully destroyed.' }
format.json { head :no_content }
end
end
def set_profile
#profile = Profile.find(params[:id])
##profile = Profile.find(profile_params)
end
private
def profile_params
params.require(:profile).permit(:full_name, :contact_number, :location, :makeup_type, :bio, :user_id, :image)
end
end
My index.html.erb for Profiles
<h1>Profiles#index</h1>
<%= search_form_for #search, url: profiles_path, html: { method: :post, :class => 'course-finder-form' } do |f| %>
<%= f.text_field :location_cont %>
<%= f.submit "Search" %>
<% end %>
My routes (I'm not sure if this would be of any relation to the issue or if I'm missing routes - again I'm not 100% but see below):
Rails.application.routes.draw do
resources :profiles
root to: 'pages#index'
devise_for :users, :controllers => { :registrations => "registrations" }
end
My schema:
ActiveRecord::Schema.define(version: 20161126221219) do
create_table "profiles", force: :cascade do |t|
t.string "full_name"
t.string "contact_number"
t.string "location"
t.string "makeup_type"
t.string "bio"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "image"
end
If you need to see my models let me know. Currently one user has one profile and a profile belongs to a user but that relationship doesn't appear to be working as it should. Anyway, that's a separate issue to this but wanted to give you as much background as possible.
Any help would be very much appreciated.
Try something like this:
#profile controller
def index
#search = Profile.search(params[:q])
#profiles = #search.result(distinct: true)
end
#profile index
<%= search_form_for #search do |f| %>
<%= f.label :location_cont, "location in profile" %><br>
<%= f.submit "Search", class:"btn btn-info btn-block" %>
<% end %>
<% #profiles.each do |profile| %>
<%= profile.name %>
<% end %>
I think you have a typo in your index.html.erb
Do you have :location_cont anywhere in your model? or is it :location

Article/post drafts in Rails

I am working on a wiki application in Rails that would be publicly editable. I have an articles controller and a drafts controller. When someone clicks 'edit' on an article, I would like to create a new draft with the contents of the original article, and then save that to the database table when the user clicks 'save'. Any ideas on how I might go about doing this? I've been stuck on it for a few days.
Currently, each article belongs_to a category, a subcategory, and has_many drafts.
Database schema:
ActiveRecord::Schema.define(version: 20160723153357) do
create_table "articles", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "title"
t.text "content"
t.integer "category_id"
t.integer "subcategory_id"
end
create_table "categories", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "drafts", force: :cascade do |t|
t.string "title"
t.text "content"
t.integer "category_id"
t.integer "subcategory_id"
t.integer "article_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "subcategories", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "category_id"
end
end
Articles_controller:
class ArticlesController < ApplicationController
before_action :set_article, only: [:show, :edit, :update, :destroy]
# GET /articles
# GET /articles.json
def index
if params[:category].blank? && params[:subcategory].blank?
#articles = Article.all.order("created_at DESC")
elsif params[:subcategory].blank?
#category_id = Category.find_by(name: params[:category]).id
#articles = Article.where(category_id: #category_id).order("created_at DESC")
else
#subcategory_id = Subcategory.find_by(name: params[:subcategory]).id
#articles = Article.where(subcategory_id: #subcategory_id).order("created_at DESC")
end
end
# GET /articles/1
# GET /articles/1.json
def show
end
# GET /articles/new
def new
#article = Article.new
end
# GET /articles/1/edit
def edit
end
# POST /articles
# POST /articles.json
def create
#parameters = article_params
#parameters[:category] = Category.find_by(id: Subcategory.find_by(id: article_params[:subcategory_id]).category_id)
#article = Article.new(#parameters)
respond_to do |format|
if #article.save
format.html { redirect_to #article, notice: 'Article was successfully created.' }
format.json { render :show, status: :created, location: #article }
else
format.html { render :new }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /articles/1
# PATCH/PUT /articles/1.json
def update
respond_to do |format|
if #article.update(article_params)
format.html { redirect_to #article, notice: 'Article was successfully updated.' }
format.json { render :show, status: :ok, location: #article }
else
format.html { render :edit }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# DELETE /articles/1
# DELETE /articles/1.json
def destroy
#article.destroy
respond_to do |format|
format.html { redirect_to articles_url, notice: 'Article was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_article
#article = Article.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def article_params
params.require(:article).permit(:title,:content,:subcategory_id)
end
end
Drafts_controller:
class DraftsController < ApplicationController
before_action :set_draft, only: [:show, :edit, :update, :destroy]
# GET /drafts
# GET /drafts.json
def index
#drafts = Draft.all
end
# GET /drafts/1
# GET /drafts/1.json
def show
end
# GET /drafts/new
def new
#draft = Draft.new
end
# GET /drafts/1/edit
def edit
end
# POST /drafts
# POST /drafts.json
def create
#parameters = draft_params
#parameters[:article_id] = params[:article_id]
#parameters[:subcategory_id] = 2
#parameters[:category_id] = 2
#draft = Draft.new(#parameters)
respond_to do |format|
if #draft.save
format.html { redirect_to #draft, notice: 'Draft was successfully created.' }
format.json { render :show, status: :created, location: #draft }
else
format.html { render :new }
format.json { render json: #draft.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /drafts/1
# PATCH/PUT /drafts/1.json
def update
respond_to do |format|
if #draft.update(draft_params)
format.html { redirect_to #draft, notice: 'Draft was successfully updated.' }
format.json { render :show, status: :ok, location: #draft }
else
format.html { render :edit }
format.json { render json: #draft.errors, status: :unprocessable_entity }
end
end
end
# DELETE /drafts/1
# DELETE /drafts/1.json
def destroy
#draft.destroy
respond_to do |format|
format.html { redirect_to drafts_url, notice: 'Draft was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_draft
#draft = Draft.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def draft_params
params.require(:draft).permit(:title, :content)
end
end
Article model:
class Article < ApplicationRecord
belongs_to :category
belongs_to :subcategory
has_many :drafts
end
Draft model:
class Draft < ApplicationRecord
belongs_to :category
belongs_to :subcategory
belongs_to :article
end
I think an approach I would probably follow would be to extract the content information to another table altogether. Here's a rough implementation I could come up with immediately:
class Article < ApplicationRecord
#column_names: ['type:string']
has_many :contents
has_one :current_content, -> { current.or(approved) }, class_name: 'Content'
delegate :title, :content, to: :current_content, allow_nil: true
end
class Content < ApplicationRecord
#column_names: ["article_id:int", "title:string", "content:text", "status:int"]
belongs_to :article
enum status: [:unapproved, :approved, :current]
end
class Draft < Article
#use STI here
end
#services/set_current_article_content.rb
class SetCurrentArticleContent
attr_reader :article, :content
def initialize(article, content)
#article = article
#content = content
end
def call
article.current_content.approved!
content.current!
end
end
#services/edit_wiki_content.rb
class EditWikiContent.rb
attr_reader :article, :content
def initialize(article, content)
#article = article
#content = content
end
def call
article.contents << content
content.save!
end
end
#services/publish_draft.rb
class PublishDraft
attr_reader :draft
def initialize(draft)
#draft = draft
end
def call
draft.becomes!(Article)
end
end
There are three services which would handle the updating and setting of the current content and also publishing the draft, you could add some additional logic in any of them. Also note the condition for the current_content in the article model, your logic might be different from the way I have implemented it.

Categories stopped saving after creating a Join table in rails

This is my first time creating a Join table and I am a bit stuck. I have two tables: Categories and Products. I originally had it set up where Products belong to on category and Categories had many products. I just created a join table and changed my associations to has_and_belongs_to_many.
I have a form where multiple categories can be selected for a product but the categories selected are not saving in the database anymore.
In my controller I have created an array for category_id in my product params and I am wondering if there is something in my database that needs to be updated as well? Should I change categroy_id in database?
Here are my tables:
create_table "categories_products", id: false, force: :cascade do |t|
t.integer "category_id", null: false
t.integer "product_id", null: false
end
create_table "categories", force: :cascade do |t|
t.string "name"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "product_id"
t.integer "category_id"
end
create_table "products", force: :cascade do |t|
t.string "title"
t.text "description"
t.string "image_url"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image", default: "{}"
t.integer "category_id"
t.integer "product_id"
end
Here are my model associations:
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories, :join_table => :categories_products
class Category < ActiveRecord::Base
has_and_belongs_to_many :products, :join_table => :categories_products
the categories selector in my new product form:
<div class="field">
<%= f.label :category_ids %><br>
<%= f.select :category_ids, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>
</div>
Products controller:
class ProductsController < ApplicationController
before_filter :authenticate_admin!, :except => [:index, :show, :earings]
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
#products = Product.all
respond_to do |format|
format.html # index.html.erb
format.js # index.js.erb
format.json { render json: #products }
end
end
def show
end
def new
#products = Product.new
#categories = Category.order(:name)
end
# GET /products/1/edit
def edit
#categories = Category.order(:name)
end
# POST /products
# POST /products.json
def create
#products = 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(:title, :description, :image, :price, :category_ids => [])
end
def search_params
default_params = {}
default_params.merge({user_id_eq: current_user.id}) if signed_in?
# more logic here
params[:q].merge(default_params)
end
end

Rails 4: issues with strong parameters and passing data

Good day, community.
First of all, I'm a newbie in Rails. I did some thing with it in College 4 years ago, and now I decided to get back on it. Lots of things changed in version 4.
Anyway, I am experiencing issues with strong parameters. Here's what I have:
I'm using Ruby 2.1, Rails 4.1.
I am trying to create a form for a hockey match with parameters (id, team_a, team_b, arena, date, score_a, score_b). team is a table (id, name) and arena is a table (id, name).
When I pass the parameters from form to the controller, the json parameters seem to be okay. But, when it is converted into match_params it is missing some values from parameters from other table. For example, I am passing arena_id: 12, but it shows arena_id: as blank.
I've spent over 5 days on this thing. Any help appreciated.
Some of the code is bellow. Let me know if you need me to provide more information...
migration data
class CreateMatches < ActiveRecord::Migration
def change
create_table :matches do |t|
t.references :team_a, default: 1 # unknown
t.references :team_b, default: 1 # unknown
t.references :arena, default: 1 # unknown
t.datetime :date
t.integer :score_a
t.integer :score_b
t.timestamps
end
add_index :matches, :team_a_id
add_index :matches, :team_b_id
add_index :matches, :arena_id
end
end
class CreateTeams < ActiveRecord::Migration
def change
create_table :teams do |t|
t.string :name, null: false
t.timestamps
end
end
end
class CreateArena < ActiveRecord::Migration
def change
create_table :arena do |t|
t.string :name, null: false
t.timestamps
end
end
end
match.rb (model)
class Match < ActiveRecord::Base
belongs_to :team_a, :class_name => 'Team'
belongs_to :team_b, :class_name => 'Team'
belongs_to :arena
end
team.rb (model)
class Team < ActiveRecord::Base
has_many :matches
accepts_nested_attributes_for :matches
end
arena.rb (model)
class Arena < ActiveRecord::Base
has_many :matches
accepts_nested_attributes_for :matches
end
matches_controller.rb
class MatchesController < ApplicationController
before_action :set_match, only: [:show, :edit, :score, :update, :destroy]
include ActionView::Helpers::DateHelper
def index
# some code
end
def show
# some code
end
def new
#match = Match.new
#teams = Team.all.order("name ASC")
#arenas = Arena.all.order("name ASC")
end
# GET /matches/1/edit
def edit
# some code
end
def create
puts YAML::dump(match_params) # Checking passed params. Output is bellow
#match = Match.new(match_params)
respond_to do |format|
if #match.save
format.html { redirect_to #match, notice: 'Match was successfully created.' }
format.json { render action: 'show', status: :created, location: #match }
else
format.html { render action: 'new' }
format.json { render json: #match.errors, status: :unprocessable_entity }
end
end
end
def update
end
def destroy
end
private
# Use callbacks to share common setup or constraints between actions.
def set_match
#match = Match.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def match_params
params.require(:match).permit(:date, :score_a, :score_b, team_a_id: [:id, :name], team_b_id: [:id, :name], arena_id: [:id, :name])
end
public
end
teams_controller.rb
class TeamsController < ApplicationController
before_action :set_team, only: [:show, :edit, :update, :destroy]
layout :false
def index
#teams = Team.all
end
def show
end
def new
#team = Team.new
end
def edit
end
def create
#team = Team.new(team_params)
respond_to do |format|
if #team.save
format.json { render action: 'show', status: :created, location: #team }
format.html { redirect_to #team, notice: 'Team was successfully created.' }
else
format.html { render action: 'new' }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #team.update(team_params)
format.json { head :no_content }
format.html { redirect_to #team, notice: 'Team was successfully updated.' }
else
format.html { render action: 'edit' }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
end
def destroy
#team.destroy
respond_to do |format|
format.html { redirect_to teams_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_team
#team = Team.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def team_params
params.require(:team).permit(:name)
end
end
arenas_controller.rb
class ArenasController < ApplicationController
before_action :set_arena, only: [:show, :edit, :update, :destroy]
layout false
def index
#arena = Arena.all
end
def show
end
def new
#arena = Arena.new
end
def edit
end
def create
#arena = Arena.new(arena_params)
respond_to do |format|
if #arena.save
format.json { render action: 'show', status: :created, location: #arena }
format.html { redirect_to #arena, notice: 'Arena was successfully created.' }
else
format.html { render action: 'new' }
format.json { render json: #arena.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #arena.update(arena_params)
format.json { head :no_content }
format.html { redirect_to #arena, notice: 'Arena was successfully updated.' }
else
format.html { render action: 'edit' }
format.json { render json: #arena.errors, status: :unprocessable_entity }
end
end
end
def destroy
#arena.destroy
respond_to do |format|
format.html { redirect_to arenas_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_arena
#arena = Arena.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def arena_params
params.require(:arena).permit(:name)
end
end
matches/_match.html.erb
<%= form_for(#match, html: {role: 'form', class: 'form-horizontal'}) do |f| %>
<% if #match.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#match.errors.count, "error") %> prohibited this match from being saved:</h2>
<ul>
<% #match.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label 'Home Team' %>
<%= f.collection_select :team_a_id, #teams, :id, :name, {prompt: true}, {class: ''} %>
<%= f.label 'Visitor Team' %>
<%= f.collection_select :team_b_id, #teams, :id, :name, {prompt: true}, {class: ''} %>
<%= f.label 'Arena' %>
<%= f.collection_select :arena_id, #arenas, :id, :name, {prompt: true}, {class: ''} %>
<%= f.label 'Date' %>
<%= f.datetime_select :date, class: 'form-control' %>
<%= f.submit value: 'Submit' %>
<% end %>
And here's what I am getting in console after dumping data:
Started POST "/matches" for 127.0.0.1 at 2014-05-06 18:24:20 -0700
Processing by MatchesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0RJjnpczVkp2unG9VITyHYC89ThgELn5kVE2wYRymBU=", "match"=>{"team_a_id"=>"24", "team_b_id"=>"27", "arena_id"=>"21", "date(1i)"=>"2014", "date(2i)"=>"5", "date(3i)"=>"6", "date(4i)"=>"18", "date(5i)"=>"24"}, "commit"=>"Update"}
User Load (0.5ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1
--- !ruby/hash:ActionController::Parameters
date(1i): '2014'
date(2i): '5'
date(3i): '6'
date(4i): '18'
date(5i): '24'
team_a_id:
team_b_id:
arena_id:
(0.2ms) BEGIN
SQL (1.5ms) INSERT INTO `matches` (`created_at`, `date`, `arena_id`, `team_a_id`, `team_b_id`, `updated_at`) VALUES ('2014-05-07 01:24:20', '2014-05-07 01:24:00', NULL, NULL, NULL, '2014-05-07 01:24:20')
(0.2ms) COMMIT
Redirected to http://localhost:3000/matches/90
Completed 302 Found in 13ms (ActiveRecord: 2.4ms)
Take a look at your match_params, and compare it to what parameters are being passed to your controller from your form.
def match_params
params.require(:match).permit(:date, :score_a, :score_b, team_a_id: [:id, :name], team_b_id: [:id, :name], area_id: [:id, :name])
end
Parameters: {"utf8"=>"✓", "authenticity_token"=>"0RJjnpczVkp2unG9VITyHYC89ThgELn5kVE2wYRymBU=", "match"=>{"team_a_id"=>"24", "team_b_id"=>"27", "arena_id"=>"21", "date(1i)"=>"2014", "date(2i)"=>"5", "date(3i)"=>"6", "date(4i)"=>"18", "date(5i)"=>"24"}, "commit"=>"Update"}
You're permitting your arena_id in match_params as an array called area_id, with elements :id and :name. However, it's being passed from your form as just arena_id. You should change your match_params function to:
def match_params
params.require(:match).permit(:date, :score_a, :score_b, :team_a_id, :team_b_id, :arena_id)
end
Note that I've also changed :team_a_id and :team_b_id to be consistent with what's being passed in your parameters too, although it doesn't look like you're passing :score_a or :score_b. You should check out strong parameters in the rails guides for more information.
Okay, I found my mistake. (Thanks to JKen13579)
I have put params in the wrong place.
It should be something like that:
def match_params
params.require(:match).permit(:date, :score_a, :score_b, :team_a_id, :team_b_id , :arena_id)
end
def team_params
params.require(:team).permit(:name, matches_params:[:id, :match_id, :name])
end
def arena_params
params.require(:arena).permit(:name, matches_params:[:id, :match_id, :name])
end
It fixed the issue.
everyting but name will be removed when you call this:
params.require(:arena).permit(:name)

Resources