Validate unique array values in Rails - ruby-on-rails

My Transaction model generates an array of unique ticket numbers based on quantity (an integer column) with the following controller logic:
#transaction.quantity.times.uniq { #transaction.ticket_numbers << rand(100000..999999) }
However, this only ensures that the numbers WITHIN the array are unique.
I need a database validation that checks ALL Transaction.ticket_numbers arrays to ensure that every value (ticket number) is unique across ALL arrays.
Here is my Transaction table within schema.rb:
create_table "transactions", force: :cascade do |t|
t.string "payee"
t.integer "quantity"
t.decimal "debt", precision: 8, scale: 2
t.string "email"
t.string "ministry"
t.integer "status"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "ticket_numbers", default: [], array: true
end
Transaction model from transaction.rb:
require 'csv'
class Transaction < ApplicationRecord
belongs_to :user
validates :email, :format => { :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/, :on => [:create, :update] }
validates :payee, presence: true
validates :quantity, numericality: { greater_than_or_equal_to: 1 }
validates :debt, numericality: { greater_than_or_equal_to: 0 }
def self.to_csv
attributes = %w{payee email ministry quantity debt status ticket_numbers}
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |transaction|
csv << attributes.map{ |attr| transaction.send(attr) }
end
end
end
end
Transaction controller:
class TransactionsController < ApplicationController
before_action :load_transaction, only: [:edit, :update, :destroy]
def create
#transaction = Transaction.new(transaction_params)
if #transaction.save
#transaction.quantity.times.uniq { #transaction.ticket_numbers << rand(100000..999999) }
end
#user = #transaction.user
#transactions = #user.transactions
respond_to do |format|
if #transaction.save && #transaction.status == 1
UserMailer.payment_confirmation(#transaction).deliver_later
format.html { redirect_to user_url(#user), notice:'Transaction added & ticket sent' }
format.json { render json: #user, status: :created, location: #user }
elsif #transaction.save && #transaction.status != 1
format.html { redirect_to user_url(#user), notice:'Transaction added' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render 'users/show' }
format.json { render json: #transaction.errors, status: :unprocessable_entity }
end
end
end
def edit
#user = current_user
end
def update
update_ticket_numbers
respond_to do |format|
if #transaction.update_attributes(transaction_params) && #transaction.status == 1
UserMailer.payment_confirmation(#transaction).deliver_later
format.html { redirect_to user_url(current_user), notice: 'Transaction info updated & confirmation email sent to payee' }
format.json { render json: current_user, status: :created, location: current_user }
elsif #transaction.update_attributes(transaction_params) && #transaction.status != 1
format.html { redirect_to user_url(current_user), notice: 'Transaction info updated' }
format.json { render json: current_user, status: :created, location: current_user }
else
format.html { render :edit }
format.json { render json: #transaction.errors, status: :unprocessable_entity }
end
end
end
def destroy
#transaction.destroy
redirect_to user_url(current_user), notice: 'Transaction deleted'
end
private
def load_transaction
#transaction = Transaction.find(params[:id])
end
def transaction_params
params.require(:transaction).permit(:payee, :email, :ministry, :debt,
:quantity, :status, :user_id, :ticket_numbers)
end
def update_ticket_numbers
if #transaction.update_attributes(transaction_params)
if #transaction.ticket_numbers.length < #transaction.quantity
i = #transaction.quantity - #transaction.ticket_numbers.length
i.times.uniq { #transaction.ticket_numbers << rand(100000..999999) }
elsif #transaction.ticket_numbers.length > #transaction.quantity
i = #transaction.ticket_numbers.length - #transaction.quantity
i.times { #transaction.ticket_numbers.pop }
end
end
end
end

You can add a custom ticket number validation to your model. You can read more about them here
class Transaction < ApplicationRecord
validate :ticket_number_uniqueness
def ticket_number_uniqueness
# First check all new ticket numbers are unique from each other
errors.add(:ticket_number, "is not unique") unless ticket_numbers == ticket_numbers.uniq
# Next check against other ticket numbers
ticket_numbers.each do |ticket|
if ::Transaction.where("ticket_numbers #> '{?}'", ticket).exists?
errors.add(:ticket_number, "is not unique")
end
end
end
end
Note: this is taking advantage of Postgres contains array method #>. You can learn more about array methods here

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.

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.

NoMethodError when generating new view

I'm working on making a simple app that has users which can have many playlists. I'm trying to render the New view of a playlist but I'm getting this error:
NoMethodError in PlaylistsController#new
undefined method `playlist' for nil:NilClass
def new
#playlist = #user.playlist.new
end
Here's some context:
EDIT: I uploaded the relevant parts of my code to a gist.github:
https://gist.github.com/izikperz/164eab76e64d375d9075
Playlist_controller.rb
class PlaylistsController < ApplicationController
before_action :set_playlist, only: [:show, :edit, :update, :destroy]
:set_user
# GET /playlists
# GET /playlists.json
def index
#playlists = Playlist.all
end
# GET /playlists/1
# GET /playlists/1.json
def show
end
# GET /playlists/new
def new
#playlist = #user.playlist.new
end
# GET /playlists/1/edit
def edit
end
# POST /playlists
# POST /playlists.json
def create
#playlist = #user.playlists.new(playlist_params)
respond_to do |format|
if #playlist.save
format.html { redirect_to #user.playlist, notice: 'Playlist was successfully created.' }
format.json { render :show, status: :created, location: #playlist }
else
format.html { render :new }
#format.json { render json: #playlist.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /playlists/1
# PATCH/PUT /playlists/1.json
def update
respond_to do |format|
if #playlist.update(playlist_params)
format.html { redirect_to #playlist, notice: 'Playlist was successfully updated.' }
format.json { render :show, status: :ok, location: #playlist }
else
format.html { render :edit }
format.json { render json: #playlist.errors, status: :unprocessable_entity }
end
end
end
# DELETE /playlists/1
# DELETE /playlists/1.json
def destroy
#playlist.destroy
respond_to do |format|
format.html { redirect_to playlists_url, notice: 'Playlist was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_user
#user = User.find_by(params[:user_id])
end
# Use callbacks to share common setup or constraints between actions.
def set_playlist
#playlist = Playlist.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def playlist_params
params.require(:playlist).permit(:user_id, :title, :img)
end
end
in my routes.rb I have:
resources :users do
resources :playlists
end
My user.rb model:
class User < ActiveRecord::Base
before_save { self.email = email.downcase }
has_secure_password
validates :password, length: { minimum: 6 }
has_many :playlists
end
Playlist.rb model:
class Playlist < ActiveRecord::Base
belongs_to :user, inverse_of: :playlist
validates :user_id, presence: true
end
My database schema:
ActiveRecord::Schema.define(version: 20141105043809) do
create_table "playlists", force: true do |t|
t.string "title"
t.string "img"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
end
create_table "users", primary_key: "user_id", force: true do |t|
t.string "name"
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
t.string "password_digest"
t.string "imgurl"
end
end
Anyone have any ideas?
The #user object in the new action is nil.
undefined method `playlist' for nil:NilClass
This is because params[:user_id] was not sent from your view.
Fix it by chaniging:
new_user_playlist_path(params[:user_id])
to:
new_user_playlist_path(user_id: params[:user_id])
After fixing that, another error will arise in the new action:
#playlist = #user.playlist.new
It should be pluralized as it is in your association:
#playlist = #user.playlists.new
#or
#playlist = #user.playlists.build
Or Simply ignore that:
#playlist = Playlist.new(user_id: #user.id)
Since the ActiveRecord Association between User and Playlist is :has_many and :belongs_to these are many to many associations. This implies that one user has more than one playlists. The association will provide you with a instance method #user.playlists not #user.playlist. Try to use the plural version. It should work.
Make sure that you are sending user_id along with form so that
#user = User.find_by(id: params[:user_id]) is not nil
and then change this
#playlist = #user.playlists.new

How to solve NoMethodError for this case?

So my rails app has a number of airport fares defined for each operator, as:
class AirportFare < ActiveRecord::Base
belongs_to :operator
end
class Operator < ActiveRecord::Base
has_many :airport_fares
end
My routes are defined as:
resources :operators do
resources :airport_fares
end
And following is my airport_fares_controller:
class AirportFaresController < ApplicationController
before_action :set_airport_fare, only: [:show, :edit, :update, :destroy]
before_action :set_operator
# GET /airport_fares
# GET /airport_fares.json
def index
#operator = Operator.find(params[:operator_id])
#airport_fares = Operator.find(params[:operator_id]).airport_fares
end
# GET /airport_fares/1
# GET /airport_fares/1.json
def show
end
# GET /airport_fares/new
def new
#airport_fare = Operator.find(params[:operator_id]).airport_fares.build
end
# GET /airport_fares/1/edit
def edit
end
# POST /airport_fares
# POST /airport_fares.json
def create
#airport_fare = Operator.find(params[:operator_id]).airport_fares.build(airport_fare_params)
respond_to do |format|
if #airport_fare.save
format.html { redirect_to #airport_fare, notice: 'Airport fare was successfully created.' }
format.json { render :show, status: :created, location: #airport_fare }
else
format.html { render :new }
format.json { render json: #airport_fare.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /airport_fares/1
# PATCH/PUT /airport_fares/1.json
def update
respond_to do |format|
if #airport_fare.update(airport_fare_params)
format.html { redirect_to #airport_fare, notice: 'Airport fare was successfully updated.' }
format.json { render :show, status: :ok, location: #airport_fare }
else
format.html { render :edit }
format.json { render json: #airport_fare.errors, status: :unprocessable_entity }
end
end
end
# DELETE /airport_fares/1
# DELETE /airport_fares/1.json
def destroy
#airport_fare.destroy
respond_to do |format|
format.html { redirect_to operator_airport_fares_path(operator_id: #operator.id), notice: 'Airport fare was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_operator
#operator = Operator.find(params[:operator_id])
end
def set_airport_fare
#airport_fare = AirportFare.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def airport_fare_params
params.require(:airport_fare).permit(:cabcat, :triptype, :triptime, :basedist, :basehr, :basechrg, :ratepkm, :waitingbtime, :waitingchrg, :notes, :operator_id)
end
end
My db schema says:
create_table "airport_fares", force: true do |t|
t.string "cabcat"
t.string "triptype"
t.string "triptime"
t.decimal "basedist", precision: 8, scale: 2
t.integer "basehr"
t.decimal "basechrg", precision: 8, scale: 2
t.decimal "ratepkm", precision: 8, scale: 2
t.integer "waitingbtime"
t.decimal "waitingchrg", precision: 8, scale: 2
t.text "notes"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "operator_id"
end
The problem is when I try this in my console: AirportFare.first.operator. This leads to the error:
NoMethodError: undefined method 'operator' for #<AirportFare>.
Where is the problem?
In new action you should do:
def new
#operator = Operator.find(params[:operator_id])
#airprot_fare = AirportFare.new
end
in your form:
<%= form_for [#operator, #airport_fare] do |f| %>
This should work.
It Should be operator.first.airport_fares. As you have has_many relationship on operators

Strong parameers throwing "Unknown key"Error

I am trying to get this model working with Strong Parameters but I can't seem to work out what I am doing wrong!?
ERROR:
Unknown key: name
Controller:
class PracticesController < ApplicationController
def practice_params
if params[:action] == 'create'
params.require(:practice).permit( :name, :billing_address, :physical_address, :phone_number, :fax_number, :emergency_contact, :emergency_phone, :email_addres, :active, :ABN, :time_zone)
elsif params[:action] == 'update'
params.require(:practice).permit( :name, :billing_address, :physical_address, :phone_number, :fax_number, :emergency_contact, :emergency_phone, :email_addres, :active, :ABN, :time_zone)
end
end
# GET /practices
# GET /practices.json
def index
#practices = Practice.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #practices }
end
end
# GET /practices/1
# GET /practices/1.json
def show
#practice = Practice.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #practice }
end
end
# GET /practices/new
# GET /practices/new.json
def new
#practice = Practice.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #practice }
end
end
# GET /practices/1/edit
def edit
#practice = Practice.find(params[:id])
end
# POST /practices
# POST /practices.json
def create
#practice = Practice.new(practice_params)
respond_to do |format|
if #practice.save
format.html { redirect_to #practice, notice: 'Practice was successfully created.' }
format.json { render json: #practice, status: :created, location: #practice }
else
format.html { render action: "new" }
format.json { render json: #practice.errors, status: :unprocessable_entity }
end
end
end
# PUT /practices/1
# PUT /practices/1.json
def update
#practice = Practice.find(practice_params)
respond_to do |format|
if #practice.update_attributes(practice_params)
format.html { redirect_to #practice, notice: 'Practice was successfully updated.' }
format.json { head :ok }
else
format.html { render action: "edit" }
format.json { render json: #practice.errors, status: :unprocessable_entity }
end
end
end
# DELETE /practices/1
# DELETE /practices/1.json
def destroy
#practice = Practice.find(params[:id])
#practice.destroy
respond_to do |format|
format.html { redirect_to practices_url }
format.json { head :ok }
end
end
end
Model:
class Practice < ActiveRecord::Base
#has_many :providers, :patients, :employees, :operatories, :clinics, :patients,
has_many :imagecategories
validates_inclusion_of :time_zone, in: ActiveSupport::TimeZone.zones_map(&:name)
def initial_setup
Operatory.create(:name => "Default Operatory", :active => true, :practice => self)
####### Create Practice Basic Accounts:
Revenue.create(:name => "General Revenue", :practice => self)
end
end
Schema (relevant part of):
create_table "practices", force: true do |t|
t.string "name"
t.text "billing_address"
t.text "physical_address"
t.string "phone_number"
t.string "fax_number"
t.string "emergency_contact"
t.string "emergency_phone"
t.string "email_address"
t.boolean "active"
t.string "ABN"
t.datetime "created_at"
t.datetime "updated_at"
t.string "time_zone"
end
Any help getting this sorted out would be much appreciated, maybe I am tired and just missing something obvious. But I copied most of the code from other controllers that are working correctly andthink I have made all the necessary adjustments. Any help would be much appreciated
PS its not just limited to the :name parameter, when I remove that one it simply starts complaining about:billing_address
In update action, change
#practice = Practice.find(practice_params)
to
#practice = Practice.find(params[:id])

Resources