I've managed to get a few HABTM relationships set up without any problems, but for some reason I can't make a belongs_to/has_many relationship record the values.
An Article belongs_to a Type (news, editorial, chronicle, etc.)
A Type has_many Articles
Schema.db shows the type_id integer column, the models use belongs_to and has_many and a drop down of article types appears in the form on the new/edit article pages.
But on choosing a type from the drop down (e.g. 'chronicle'), it says it creates or edits the article successfully but does not register the link between the article and 'chronicle'. On going back to edit the same article, the drop down just shows the top type ('analysis'), not 'chronicle'.
So not sure where I'm going wrong. Here are all the relevant bits, starting with the database.
From schema.db:
create_table "articles", force: :cascade do |t|
t.string "headline"
t.string "lede"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "type_id"
end
create_table "types", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Then the models:
class Article < ActiveRecord::Base
has_and_belongs_to_many :categories
has_and_belongs_to_many :regions
has_and_belongs_to_many :stories
belongs_to :type
end
class Type < ActiveRecord::Base
has_many :articles
end
And the articles controller:
# GET /articles/new
def new
#article = Article.new
#regions = Region.all.order(:region)
#categories = Category.all.order(:category)
#stories = Story.all.order(:story)
#types = Type.all.order(:name)
end
# GET /articles/1/edit
def edit
#regions = Region.all.order(:region)
#categories = Category.all.order(:category)
#stories = Story.all.order(:story)
#types = Type.all.order(:name)
end
# POST /articles
# POST /articles.json
def create
#article = Article.new(article_params)
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
/* …and then at the bottom… */
def article_params
params.require(:article).permit(:headline, :lede, :body, :category_ids => [], :region_ids => [], :story_ids => [], :type_id => [])
end
And finally in the articles form:
<strong>Type:</strong> <%= f.collection_select :type_id, #types, :id, :name %>
Any ideas?
You need to change the article_params to below
def article_params
params.require(:article).permit(:headline, :lede, :body, :type_id, :category_ids => [], :region_ids => [], :story_ids => [])
end
Notice the change :type_id => [] to :type_id
As there will be only one type_id in each articles record, your required params should not contain array of type_id. so change it to only :type_id instead of :type_id => []
def article_params
params.require(:article).permit(:headline, :lede, :body, :type_id, :category_ids => [], :region_ids => [], :story_ids => [])
end
Related
A little bit of background: I recently got a new job as a Rails developer which is all fine and dandy (I have a Rails background), but I am running into a problem and I cannot figure it out. The job I took involved taking over a project someone else at the company started but never finished. So I have a unfinished CRM application in my lap, and need the help of more experienced developers to point me in the right direction.
When I try to create a new job, I get an error "ActiveModel::MissingAttributeError in Jobs#new", followed by "can't write unknown attribute `opportunity_id'".
The error from the terminal is:
Started GET "/jobs/new" for 127.0.0.1 at 2016-08-17 10:07:44 -0700
Processing by JobsController#new as HTML
Rendered jobs/new.html.erb within layouts/application (2.0ms)
Completed 500 Internal Server Error in 10ms
ActionView::Template::Error (can't write unknown attribute `opportunity_id'):
1: <% #job[:opportunity_id] = params[:opportunity_id] %>
2: <% title "New #{#job.opportunity.name} Job"%>
3:
4: <%
app/views/jobs/new.html.erb:1:in `_app_views_jobs_new_html_erb__443350051_40007592'
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.1.4/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.1.4/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.1.4/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb within rescues/layout (34.0ms)
The error comes from line 1 which is:
<% #job[:opportunity_id] = params[:opportunity_id] %>
UPDATED: Added job model and job controller, along with the view and jobs table from shcema.rb file.
Job Model:
class Job < ActiveRecord::Base
mount_uploader :file1, AttachmentUploader
belongs_to :cost_proposal
has_many :opportunities
end
Job Controller:
class JobsController < ApplicationController
before_action :set_job, only: [:show, :edit, :update, :destroy]
skip_load_and_authorize_resource
# GET /jobs
# GET /jobs.json
def index
#jobs = Job.all
end
# GET /jobs/1
# GET /jobs/1.json
def show
end
# GET /jobs/new
def new
end
# GET /jobs/1/edit
def edit
end
# POST /jobs
# POST /jobs.json
def create
#job = Job.new(job_params)
respond_to do |format|
if #job.save
format.html { redirect_to #job, notice: 'Job was successfully created.' }
format.json { render :show, status: :created, location: #job }
else
format.html { render :new }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /jobs/1
# PATCH/PUT /jobs/1.json
def update
respond_to do |format|
if #job.update(job_params)
format.html { redirect_to #job, notice: 'Job was successfully updated.' }
format.json { render :show, status: :ok, location: #job }
else
format.html { render :edit }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
# DELETE /jobs/1
# DELETE /jobs/1.json
def destroy
#job.destroy
respond_to do |format|
format.html { redirect_to jobs_url, notice: 'Job was successfully deleted.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_job
#job = Job.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def job_params
params.require(:job).permit(:opportunity_id, :number, :name, :flight_date, :flight_sub, :camera, :roll, :map_type, :plan_only, :lab_only, :est_hrs_model, :due_date, :edge_job_id, :custom_trans, :comp_inhouse, :delivered_date, :done, :control_in, :control_status, :at_date, :control_results, :control_check, :scan_staff, :scan_date, :scan_check, :comp_staff, :comp_date, :comp_check, :comp_sub, :comp_sub_due_date, :comp_sub_rec, :img_staff, :img_date, :img_check, :edit_staff, :edit_date, :edit_check, :notes, :file1, :file2, :file3, :file4, :file5, :add_files)
end
end
Jobs table from schema.rb:
create_table "jobs", force: true do |t|
t.integer "cost_proposal_id"
t.string "number"
t.string "name"
t.date "flight_date"
t.string "flight_sub"
t.string "camera"
t.string "roll"
t.string "map_type"
t.integer "plan_only"
t.integer "lab_only"
t.integer "est_hrs_model"
t.date "due_date"
t.integer "edge_job_id"
t.integer "custom_trans"
t.integer "comp_inhouse"
t.date "delivered_date"
t.integer "done"
t.date "control_in"
t.string "control_status"
t.date "at_date"
t.string "control_results"
t.integer "control_check"
t.string "scan_staff"
t.date "scan_date"
t.integer "scan_check"
t.string "comp_staff"
t.date "comp_date"
t.integer "comp_check"
t.string "comp_sub"
t.date "comp_sub_due_date"
t.integer "comp_sub_rec"
t.string "img_staff"
t.date "img_date"
t.integer "img_check"
t.string "edit_staff"
t.date "edit_date"
t.integer "edit_check"
t.text "notes"
t.string "file1"
t.string "file2"
t.string "file3"
t.string "file4"
t.string "file5"
t.string "add_files"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "flown"
t.integer "cust_trans"
t.integer "delivered"
t.string "at_staff"
t.integer "at_check"
end
Opportunities table from schema.rb:
create_table "opportunities", force: true do |t|
t.integer "employee_id"
t.integer "emp2_id"
t.integer "emp3_id"
t.string "name"
t.datetime "prop_date"
t.integer "opp_status_id"
t.string "delay"
t.date "con_signed"
t.integer "quote_won_id"
t.float "total_cost"
t.date "exp_close"
t.integer "pri_comp_id"
t.text "notes"
t.datetime "created_at"
t.datetime "updated_at"
t.string "lost"
t.string "won"
t.string "location"
t.integer "pm_id"
end
Jobs new view (where error is occuring):
<% #job[:opportunity_id] = params[:opportunity_id] %>
<% title "New #{#job.opportunity.name} Job"%>
<%
#job[:name] = #job.opportunity.name
#pm = #job.opportunity.pm_id
%>
<br><br>
<%= render 'form' %>
If you need more files from the project, let me know. Thanks in advance!
An ActiveModel::MissingAttributeError is raised when you try to set an attribute on a model which does not exist. Remember that ActiveRecord "automagically" creates setters and getters by reading the schema from the database.
The most common reasons are:
typo (for example the db column is named oportunity_id)
the migration which adds the column to the schema has not been run
there is no migration to add the column
Also assigning attributes to the model in the view is a pretty bad code smell. Do it in the controller instead:
class JobsController < ApplicationController
# ...
def new
#job = Job.new do |j|
if params[:opportunity_id].present?
j.opportunity_id = params[:opportunity_id]
end
end
end
# ...
end
On line 2 of your view, it looks like you're expecting new jobs to already have an associated opportunity.
<% title "New #{#job.opportunity.name} Job"%>
If this is the case, then the job routes should be nested under opportunities. So in config/routes.rb
resources :opportunities do
resources :jobs
end
You can then create new jobs through http://localhost:3000/opportunities/:id/jobs/new
And in your JobsController:
def new
#opportunity = Opportunity.find(params[:opportunity_id])
#job = Job.new(opportunity: #opportunity)
# ...
So when I look through your two table definitions I see that 1) there is no opportunity_id key in jobs and conversely, 2) no job_id key in opportunities. In order for your has_many :opportunities to work, you need to add a job_id field to the opportunities table. Here is a vastly simplified example of what I mean:
def Job < ActiveRecord::Base
has_many :opportunities
end
def Opportunity < ActiveRecord::Base
end # shown for completeness of answer only
You will need to add the job_id foreign key to the opportunities table with a migration, for example:
class AddJobForeignKeyToOpportunities < ActiveRecord::Migration
def change
add_column :opportunities, :job_id, :integer
end
end
If you're unsure how to deal with the migration, check out the Rails Guide for the rails command-line tool. Once you have that in place Rails will automagically give you access to the Opportunities associated with a Job as you might expect:
job = Job.first
job.opportunities
Keep in mind that you still won't be able to access job.opportunity_id as the error in your original question mentions. The many to one association you've set up requires that the Opportunity model have the foreign key. However, Rails will give you access to job.opportunity_ids plural.
[edit] To add an opportunity to a job you'll want to do something along the lines of:
opportunity = Opportunity.find(params[:opportunity_id])
job.opportunities << opportunity
You should always avoid referring to the foreign key directly on the associated model. Someone said this somewhere in another answer or comment here but I can't find it to credit them.
Instead rely on the Rails provided methods. In this example above, the << operator is effectively setting job_id on the opportunity to link them up.
I have setup has_many and has_many :through association between a Order,User,Product and Order_detail model as a join table.
Models:
class Order < ActiveRecord::Base
has_many :order_details
belongs_to :user
has_many :products, through: :order_details
end
class OrderDetail < ActiveRecord::Base
belongs_to :order
belongs_to :product
end
class Product < ActiveRecord::Base
has_many :order_details
has_many :orders, through: :order_details
end
class User < ActiveRecord::Base
has_many :orders
end
How to save automatically for join table order_details.
Now data save only to order table.
Need to save all products to order_tables for current order and user
class OrdersController < ApplicationController
before_action :authenticate_user!
def index
#order = Order.all
end
def new
# #order = Order.new
#order = current_user.orders.new
end
def create
#order = current_user.orders.new(order_params)
#order.date = Date.today.to_s
if #order.save
# i think this is bad wrong to implementation of functional)
# params[:product_id].each do |detail_product_id|
# #order.order_details.product_id = detail_product_id
# #order.order_details.user_id = current_user
# #order.order_details.save
flash[:success] = "Order was successfully submitted"
redirect_to new_order_path
else
render :new
end
end
private
def order_params
params.require(:order).permit(:date, :product_id => [])
end
end
My schema:
create_table "order_details", force: true do |t|
t.integer "order_id"
t.integer "product_id"
t.integer "quantity"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "orders", force: true do |t|
t.integer "user_id"
t.date "date"
end
add_index "orders", ["user_id"], name: "index_orders_on_user_id", using: :btree
create_table "orders_products", id: false, force: true do |t|
t.integer "order_id"
t.integer "product_id"
end
create_table "products", force: true do |t|
t.string "product_name"
t.integer "product_price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "available_status"
t.string "product_type"
end
In your view, add fields for order_details like:
<%= f.fields_for :order_details do |od| %>
<%= od.label 'your attribute for OrderDetail' %>
<%= # od.text_field 'your attribute' %>
<% end %>
Then in your model, accept nested attributes for order_details
like:
accepts_nested_attributes_for :order_details
These are sample values, you can use this logic with your actual attributes.
In your controller, permit attributes for order_details like:
params.require(:order).permit(:id, :name, order_details: [
#attributes of order details
])
Assuming that product_ids is an array of the product ids that you wish to add to the order, you could try assigning them in the following way and Rails should automagically create those association records for order_details when you then call #order.save
#order.products << Product.find_by_id(product_ids)
Am i right add that rows for controller?
Order_controller:
def create
#order = current_user.orders.new(order_params)
#order.products = Product.find_by_id(order_params[:product_ids])
#order.date = Date.today.to_s
if #order.save
flash[:success] = "Order was successfully submitted"
redirect_to new_order_path
else
render :new
end
end
private
def order_params
params.require(:order).permit(:date, order_details: [:product_id])
end
end
order model:
accepts_nested_attributes_for :order_details
I'm trying to save from 3 different types of products.
But how to take one product id from each part ? Because now I can choose only one product from all
View:
= simple_form_for(#order, html: {:class => 'well form-horizontal', :method => :post, :action=> :create }) do |f|
.col-xs-12.col-sm-6.col-md-8
= render 'shared/error_messages', object: f.object
%br
= simple_fields_for :order_details do |od|
= od.collection_radio_buttons :product_ids, Product.get_first_course, :id, :product_name ,:item_wrapper_class => 'inline'
%hr
= od.collection_radio_buttons :product_ids, Product.get_main_course, :id, :product_name, :item_wrapper_class => 'inline'
%hr
= od.collection_radio_buttons :product_ids, Product.get_drink, :id, :product_name,:item_wrapper_class => 'inline'
%hr
= f.button :submit, class: "btn btn-primary"
I change my association type to HABTM and that's enough for my situation. So..
models:
class Order < ActiveRecord::Base
has_and_belongs_to_many :products
before_destroy { products.clear }
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :orders
end
Order_controller:
def create
order = current_user.orders.new(date: Date.today.to_s)
#order_products = Product.where(id: order_params[:product_ids])
order.products << #order_products
if order.save
#blalblal - sucsess
else
#blabla - alert-notice
end
I am new to rails 4.I used nested attributes for multiple image upload.But i'm having few problems with this
im getting ActiveRecord::StatementInvalid in Products#index
Mysql2::Error: Unknown column 'pictures.product_id' in 'where clause': SELECT pictures. FROM pictures WHERE pictures.product_id = 11* error
My models are as follows
class Picture < ActiveRecord::Base
belongs_to :product
has_attached_file :image
end
class Product < ActiveRecord::Base
belongs_to :user
belongs_to :category
has_many :comments , dependent: :destroy
has_many :pictures
accepts_nested_attributes_for :pictures
end
products_controller.rb
class ProductsController < ApplicationController
def show
#product = Product.find(params[:id])
#comment = #product.comments.build
#category_id = #product.category_id
#category1 = Category.find_by(id: #category_id)
end
def new
#product = current_user.products.build
#product.pictures.build
end
def create
#product = current_user.Product.new(product_params)
#product.save
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
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
def product_params
params.require(:product).permit(:name, :price, :description, :reason, :user_id,:status,:category_id,pictures_attributes: [:image])
end
def correct_user
#product = current_user.products.find_by(id: params[:id])
redirect_to root_url if #product.nil?
end
end
Schema.rb
ActiveRecord::Schema.define(version: 20151226132302) do
create_table "pictures", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "products", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name", limit: 255
t.integer "price", limit: 4
t.text "description", limit: 65535
t.text "reason", limit: 65535
t.integer "user_id", limit: 4
t.string "image_file_name", limit: 255
t.string "image_content_type", limit: 255
t.integer "image_file_size", limit: 4
t.datetime "image_updated_at"
t.string "status", limit: 255
t.integer "category_id", limit: 4
t.integer "product_id", limit: 4
end
end
My migration file
20151226132302_add_product_id_to_product.rb
class AddProductIdToPictures < ActiveRecord::Migration
def change
add_reference :pictures, :product, index: true
end
end
Even with above migration product_id is not added to pictures model.
Can somebody help me with this?
It will be helpful if someone can give me nice reference for RAILS 4
unknown attribute 'product_id'
Suggests you don't have the product_id column in your pictures table.
If you're using has_many / belongs_to, you'll need to set the foreign_key for your belongs_to model in its table:
If you don't have the product_id column in your pictures table, you'll need to use the following:
$ rails g migration AddProductIdToPictures
# db/migrate/add_product_id_to_pictures_________.rb
class AddProductIdToPictures < ActiveRecord::Migration
def change
add_reference :pictures, :product, index: true
end
end
$ rake db:migrate
Ref: Add a reference column migration in Rails 4
Another issue you may have is that you're using .build in the new method. I know that new and build have very little difference, but I was under the impression to use new:
def new
#product = current_user.products.new
#product.pictures.build
end
You've also got an error in your create action:
def create
#NO - #product = current_user.Product.new(product_params) #-> cannot use constant
#Should be this:
#product = current_user.products.new
#product.save
end
i have such model:
class ToType < ActiveRecord::Base
attr_accessible :Name, :TYP_CCM, :TYP_CCM_TAX, :TYP_CDS_ID, :TYP_CTM, :TYP_CYLINDERS, :TYP_DOORS, :TYP_HP_FROM, :TYP_HP_UPTO, :TYP_ID, :TYP_KV_ABS_DES_ID, :TYP_KV_ASR_DES_ID, :TYP_KV_AXLE_DES_ID, :TYP_KV_BODY_DES_ID, :TYP_KV_BRAKE_SYST_DES_ID, :TYP_KV_BRAKE_TYPE_DES_ID, :TYP_KV_CATALYST_DES_ID, :TYP_KV_DRIVE_DES_ID, :TYP_KV_ENGINE_DES_ID, :TYP_KV_FUEL_DES_ID, :TYP_KV_FUEL_SUPPLY_DES_ID, :TYP_KV_MODEL_DES_ID, :TYP_KV_STEERING_DES_ID, :TYP_KV_STEERING_SIDE_DES_ID, :TYP_KV_TRANS_DES_ID, :TYP_KV_VOLTAGE_DES_ID, :TYP_KW_FROM, :TYP_KW_UPTO, :TYP_LA_CTM, :TYP_LITRES, :TYP_MAX_WEIGHT, :TYP_MMT_CDS_ID, :TYP_MOD_ID, :TYP_PCON_END, :TYP_PCON_START, :TYP_RT_EXISTS, :TYP_SORT, :TYP_TANK, :TYP_VALVES, :is_in_to
set_primary_key :TYP_ID
belongs_to :to_model
has_many :to_articles, :dependent => :destroy
end
class ToArticle < ActiveRecord::Base
attr_accessible :details, :manufacturer, :name, :oem_number, :only_with_vin, :quantity, :type_id
belongs_to :to_type
end
(some db is converted from big catalog, so rails conventions are a little bit missed)
my show view of to_type is:
part of it:
%td
= link_to "Подробнее", admin_catalog_to_to_article_path(c), :class=>'btn btn-primary'
= link_to "Редактирование", edit_admin_catalog_to_to_type_path(c), :class=>'btn btn-warning'
= link_to "Удалить", admin_catalog_to_to_type_path(c), :confirm => "!!!Тип #{c.Name} будет удалён!!!! Вы уверены?", :method => :delete, :class => "btn btn-danger"
my show action work normally, also controller:
class Admin::Catalog::To::ToTypesController < ApplicationController
respond_to :html
before_filter :auth_user
def auth_user
redirect_to new_admin_session_path unless admin_signed_in?
end
def show
#mod_id = params[:id]
#man = ToType.find(:all, conditions: {:TYP_MOD_ID => #mod_id}, order: "Name ASC")
render :layout => 'admin'
end
def edit
#man = ToType.find(params[:id])
render :layout => 'admin'
end
def update
#man = ToType.find(params[:id])
if #man.update_attributes(params[:to_type])
redirect_to admin_catalog_to_to_type_path(#man.TYP_MOD_ID)
else
render :layout => 'admin'
end
end
def new
#man = ToType.new
#mod_id = params[:mod_id]
render :layout => 'admin'
end
def create
#man = ToType.new(params[:to_type])
#mod_id = params[:mod_id]
#man.TYP_MOD_ID = #mod_id
if #man.save
redirect_to admin_catalog_to_to_type_path(#mod_id)
else
render :layout => 'admin'
end
end
def destroy
#man = ToType.find(params[:id])
if #man.destroy
redirect_to admin_catalog_to_to_type_path(#man.TYP_MOD_ID)
else
render :layout => 'admin'
end
end
end
and route:
namespace :admin do
namespace :catalog do
namespace :to do
resources :to_manufacturers,
:to_models,
:to_types,
:to_articles
end
end
end
but when i try to call destroy method i get:
ActiveRecord::StatementInvalid in Admin::Catalog::To::ToTypesController#destroy
Mysql2::Error: Unknown column 'to_articles.to_type_id' in 'where clause': SELECT `to_articles`.* FROM `to_articles` WHERE `to_articles`.`to_type_id` = 26923
also when i try edit or create i get:
undefined method `model_name' for NilClass:Class
i think that something is bad with connection with model: with update and create it didn't initialize object.
With destroy it use other! db. What happens?
Also i try to recreate it all and rename, nothing... Could understand what wrong... Also when in model i write which db table to use same errors appear.
when i try to add new object via console all is ok.
upd:
class CreateToTypes < ActiveRecord::Migration
def change
create_table :to_types, :primary_key => :TYP_ID do |t|
t.integer :TYP_ID
t.integer :TYP_CDS_ID
t.integer :TYP_MMT_CDS_ID
t.integer :TYP_MOD_ID
t.binary :TYP_CTM
t.binary :TYP_LA_CTM
t.integer :TYP_SORT
t.integer :TYP_PCON_START
t.integer :TYP_PCON_END
t.integer :TYP_KW_FROM
t.integer :TYP_KW_UPTO
t.integer :TYP_HP_FROM
t.integer :TYP_HP_UPTO
t.integer :TYP_CCM
t.integer :TYP_CYLINDERS
t.integer :TYP_DOORS
t.integer :TYP_TANK
t.integer :TYP_KV_VOLTAGE_DES_ID
t.integer :TYP_KV_ABS_DES_ID
t.integer :TYP_KV_ASR_DES_ID
t.integer :TYP_KV_ENGINE_DES_ID
t.integer :TYP_KV_BRAKE_TYPE_DES_ID
t.integer :TYP_KV_BRAKE_SYST_DES_ID
t.integer :TYP_KV_FUEL_DES_ID
t.integer :TYP_KV_CATALYST_DES_ID
t.integer :TYP_KV_BODY_DES_ID
t.integer :TYP_KV_STEERING_DES_ID
t.integer :TYP_KV_STEERING_SIDE_DES_ID
t.float :TYP_MAX_WEIGHT
t.integer :TYP_KV_MODEL_DES_ID
t.integer :TYP_KV_AXLE_DES_ID
t.integer :TYP_CCM_TAX
t.float :TYP_LITRES
t.integer :TYP_KV_DRIVE_DES_ID
t.integer :TYP_KV_TRANS_DES_ID
t.integer :TYP_KV_FUEL_SUPPLY_DES_ID
t.integer :TYP_VALVES
t.integer :TYP_RT_EXISTS
t.string :Name
t.boolean :is_in_to
t.string :fuel_type
end
end
end
class CreateToArticles < ActiveRecord::Migration
def change
create_table :to_articles do |t|
t.string :oem_number
t.string :manufacturer
t.text :name
t.integer :quantity
t.text :details
t.boolean :only_with_vin
end
end
end
you don't have relationship between ToArticle and ToType in database.
use belongs_to in ToArticle migration
check rails guide on associations
I have a couple models (Site and Server) that are related to eachother via has_many :through. they also both belong_to :user. in my sites/new view, I create a new site, and I create a new server using a nested form.fields_for :servers. Everything works as expected, except for that the server that ends up getting created doesn't have a user_id populated. How do i ensure it is?
My sites_controller new and create methods:
def new
#user = current_user
#site = #user.sites.build
#servers = #user.servers.all
# let there be one server linked
#site.site_servers.build
# #user.servers.build if #user.servers.empty?
#site.servers.build( :user_id => current_user.id ) if #site.servers.empty?
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #site }
end
end
def create
#site = current_user.sites.build(params[:site])
respond_to do |format|
if #site.save
flash[:notice] = 'Site was successfully created.'
format.html { redirect_to(#site) }
format.xml { render :xml => #site, :status => :created, :location => #site }
else
format.html { render :action => "new" }
format.xml { render :xml => #site.errors, :status => :unprocessable_entity }
end
end
end
If you notice the commented lines, those are things I tried that didn't work.
Models:
class User < ActiveRecord::Base
acts_as_authentic
has_many :sites
has_many :servers
end
class Site < ActiveRecord::Base
belongs_to :user
has_many :site_servers
has_many :servers, :through => :site_servers
accepts_nested_attributes_for :site_servers, :allow_destroy => true
accepts_nested_attributes_for :servers, :allow_destroy => true
validates_presence_of :name, :on => :create, :message => "Name is required"
end
class Server < ActiveRecord::Base
attr_encrypted :password, :key => '393b79433f616f445f652a752d', :attribute => 'crypted_password'
belongs_to :user
has_many :site_servers
has_many :sites, :through => :site_servers
validates_presence_of :url, :on => :create, :message => "URL is required."
validates_presence_of :username, :on => :create, :message => "Username is required."
validates_presence_of :password, :on => :create, :message => "Password is required."
def name
username + "#" + url
end
def to_s
name
end
end
class SiteServer < ActiveRecord::Base
belongs_to :site
belongs_to :server
has_one :user, :through => :site
end
And here's my schema:
ActiveRecord::Schema.define(:version => 20091203045550) do
create_table "servers", :force => true do |t|
t.string "url"
t.string "username"
t.string "crypted_password"
t.integer "port"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "site_servers", :force => true do |t|
t.integer "site_id"
t.integer "server_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "sites", :force => true do |t|
t.string "name"
t.string "url"
t.string "path"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", :force => true do |t|
t.string "username"
t.string "email"
t.string "crypted_password"
t.string "password_salt"
t.string "persistence_token"
t.datetime "created_at"
t.datetime "updated_at"
end
end
Do you have a hidden field for the user_id in the server form?
<%= f.hidden_field :user_id %>
If not, the value is not getting passed back, even if you managed to properly set it. The line you have commented out would have worked, if you add a hidden field to the form.
#site.servers.build(:user_id => current_user.id) if #site.servers.empty?
I actually like the idea of setting the user id in the create method better, because otherwise you introduce the possibility of someone crafting up their own form submission and creating things under other people's user ids. I don't know if security is a big deal in your app, but I never trust a user id that is sent from a form.
I'm guessing the problem is in your create action. The new action just builds Ruby objects -- you need to make sure there is similar build code in the create action:
def create
#site = current_user.sites.build(params[:site])
#site.save
end