简体   繁体   中英

RoR - SQLite3::SQLException: no such column: - Rails not appending _id to generated query

I have two model objects LineItemClass and LineItemSubClass. I am trying to add a new LineItemSubClass to a LineItemClass, and it is generating an SQL error:

SQLite3::SQLException: no such column: line_item_sub_classes.line_item_class.

The correct query should be something more like line_item_sub_classes.line_item_class_id .

I used generate to create everything, so I am fairly confused as to why this is happening. In researching the problem, everywhere else I have seen the SQL eception, the generated query had _id. My only thought is that I am doing something wrong with resources that have multiple word names - are there any good docs on conventions for multiple word names?

schema.rb

ActiveRecord::Schema.define(:version => 20130905194234) do
  create_`enter code here`table "line_item_classes", :force => true do |t|
    t.string   "code"
    t.string   "name"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end

  create_table "line_item_sub_classes", :force => true do |t|
    t.string   "code"
    t.string   "name"
    t.integer  "line_item_class_id"
    t.datetime "created_at",         :null => false
    t.datetime "updated_at",         :null => false
  end

  add_index "line_item_sub_classes", ["line_item_class_id"], :name =>"index_line_item_sub_classes_on_line_item_class_id"
end

line_item_class.rb

class LineItemClass < ActiveRecord::Base 
  include ActiveModel::ForbiddenAttributesProtection

  has_many :line_item_sub_classes

  attr_accessible :code, :name

  validates :code, presence: true, length: {is: 2}, uniqueness: true
  validates :name, presence: true, length: {maximum: 100}, uniqueness: true
end

line_item_sub_class.rb

class LineItemSubClass < ActiveRecord::Base
  include ActiveModel::ForbiddenAttributesProtection

  belongs_to :line_item_class

  attr_accessible :code, :name

  validates :code, presence: true, length: {is: 2}, :uniqueness => {:scope => :line_item_class}
  validates :name, presence: true, length: {maximum: 100}, :uniqueness => {:scope => :line_item_class}
end

offending code from line_item_sub_classes_controller.rb

class LineItemSubClassesController < ApplicationController
  def create
    @line_item_class = LineItemClass.find(params[:line_item_class_id])
    @line_item_sub_class = 
      @line_item_class.line_item_sub_classes.
      create(params[:line_item_sub_class].permit(:code, :name))
    redirect_to line_item_class_path(@line_item_class)
  end
end

from the view, here is the form section - this is what creates the params right?

<%= form_for([@line_item_class,
              @line_item_class.line_item_sub_classes.build]) do |f| %>
  <p>
    <%= f.label :code %><br />
    <%= f.text_field :code %>
  </p>
  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>

the form tag in the output html is

<form accept-charset="UTF-8" action="/line_item_classes/1/line_item_sub_classes" class="new_line_item_sub_class" id="new_line_item_sub_class" method="post">

The error is being generated by the controller, in line

@line_item_sub_class = @line_item_class.line_item_sub_classes.create(params[:line_item_sub_class].permit(:code, :name))

I tried splitting this into two lines, but it didn't help. The update line threw a nil object exception.

@line_item_sub_class =@line_item_class.line_item_sub_classes.new
@line_item_sub_class.update_attributes(params[:line_item_sub_class].permit(:code, :name))

full error is;

SQLite3::SQLException: no such column: line_item_sub_classes.line_item_class: SELECT 1 AS one FROM "line_item_sub_classes" WHERE ("line_item_sub_classes"."code" = 'A0' AND "line_item_sub_classes"."line_item_class" IS NULL) LIMIT 1. 

I don't have a clue what the railsmagic is doing here, but I can't imagine why this query would ever be needed. It seems like it couldn't be run until after the record existed.

ANSWER - SORT OF... I have fixed the error by changing the scope of the uniqueness validators in the LineItemSubClass model.

  validates :code, presence: true, length: {is: 2}, :uniqueness => {:scope => :line_item_class}
  validates :name, presence: true, length: {maximum: 100}, :uniqueness => {:scope => :line_item_class}

is now

  validates :code, presence: true, length: {is: 2}, :uniqueness => {:scope => :line_item_class_id}
  validates :name, presence: true, length: {maximum: 100}, :uniqueness => {:scope => :line_item_class_id}

This works. I can now create a nested LineItemSubClass without an error, but my RoR-sense is tingling. It seems like Rails should be able to infer the name of the relevant database column when I scope uniqueness to an existing association. Coding the name of a database column seems fragile. Am I doing something wrong?

So, your parameters are:

{ "utf8"=>"✓", 
  "authenticity_token"=>"Lj8iy9VkzdWrvN4LyzXQ5BY7FdpV57l12Euqtch9RtQ=",
  "line_item_sub_class"=>{   // These are the only parameters that will get
    "code"=>"A0",            // considered when creating your new
    "name"=>"Panel Box"      // LineItemSubClass record in the DB
  }, 
  "commit"=>"Create Line item sub class",
  "action"=>"create",
  "controller"=>"line_item_sub_classes",
  "line_item_class_id"=>"1"  // But this parameter needs to be included
                             // needs to be included to set the
                             // line_item_sub_classes.line_item_class_id field
}

It looks like, in your controller, you're using params[:line_item_sub_class] to create the new record. So, I think first of all that you need to change your form so that...

params[:line_item_class_id]

...is actually under

params[:line_item_sub_class][:line_item_class_id]

That will take you part of the way there. However, I don't think that will necessarily fix your entire issue. Can you update your question with:

  1. the SQL query output from this action being called
  2. the filename and line number on which you're getting this error

If you want you can just post the entire rails log output when this controller action is called. It thank that will demystify it enough (I hope) to get it solved.

Another way to say this is that your form is passing in a structure of parameters that don't quite seem to line up with what your controller is expecting, and that's probably most of the problem. So, believe it or not, look at your view, the HTML it produces, and try to figure out why the parameters in it don't match what rails is expecting in terms of structure and naming. If you can figure that out you'll be most of the way there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM