Unknown primary key for table - ruby-on-rails

I'm making an extension for refinerycms in rails and this is the structure I follow :
Project has many project_images
Project_images belongs_to Project & Image ( The refinery Image class )
Now when I want to create a new object of ProjectImage in my Project class I always get this error :
Unknown primary key for table refinery_projects_images in model Refinery::Projects::ProjectImage.
I don't need a primary key for this table because it is a join table. Here is the code of my models and migration file:
Migration.rb
class CreateProjectsProjects < ActiveRecord::Migration
def up
create_table :refinery_projects do |t|
t.string :title
t.text :description
t.string :investor
t.string :location
t.string :area
t.string :purpose
t.string :architect
t.string :users
t.integer :position
t.integer :position
t.timestamps
end
add_index :refinery_projects, :id
create_table :refinery_projects_images, :id => false do |t|
t.references :image
t.references :project
t.integer :position
t.string :category
t.string :caption
end
add_index :refinery_projects_images, [:image_id, :project_id], :uniq => true
end
def down
if defined?(::Refinery::UserPlugin)
::Refinery::UserPlugin.destroy_all({:name => "refinerycms-projects"})
end
if defined?(::Refinery::Page)
::Refinery::Page.delete_all({:link_url => "/projects/projects"})
end
drop_table :refinery_projects
drop_table :refinery_projects_images
end
end
Project.rb
module Refinery
module Projects
class Project < Refinery::Core::BaseModel
self.table_name = 'refinery_projects'
attr_accessible :title, :description, :investor, :location, :area, :purpose, :architect, :users, :position, :position, :images_attributes
acts_as_indexed :fields => [:title, :description, :investor, :location, :area, :purpose, :architect, :users]
validates :title, :presence => true, :uniqueness => true
has_many :project_images
has_many :images, :through => :project_images, :order => 'position ASC'
accepts_nested_attributes_for :images, :allow_destroy => false
def images_attributes=(data)
ProjectImage.delete_all(:project_id => self.id)
(0..(data.length-1)).each do |i|
unless (image_data = data[i.to_s]).nil? or image_data['id'].blank?
project_image = self.project_images.new(:image_id => image_data['id'].to_i, :position => i)
# Add caption if supported
if false
project_image.caption = image_data['caption']
end
self.project_images << project_image
end
end
end
end
end
end
ProjectImage.rb
module Refinery
module Projects
class ProjectImage < Refinery::Core::BaseModel
self.table_name = 'refinery_projects_images'
attr_accessible :image_id, :position
belongs_to :image, :class_name => 'Refinery::Image'
belongs_to :project, :class_name => 'Refinery::Projects::Project'
end
end
end
Somebody knows why he keeps looking for the primary key?

Refinery::Core::BaseModel is somehow derived from ActiveRecord::Base. When you use that class then your table layout needs an id. If you don't want an id, Have a look at has_and_belongs_to_many in the rails guides: http://guides.rubyonrails.org/association_basics.html

Related

Building Rails Forms for saving Polymorphic Associations

I have categories model which I would like to be able to use with different models. That's how I ended up using Polymorphic with has_many.
With Rails_admin everything works without a problem. But, when I want to create a form by myself, I can't seem to make it save. Here is what I have:
category.rb
class Category < ActiveRecord::Base
has_many :categorizings, inverse_of: :category, dependent: :destroy
has_many :cars, through: :categorizings, :source => :categorizable,
:source_type => 'Car'
end
categorizing.rb
class Categorizing < ActiveRecord::Base
belongs_to :category
belongs_to :categorizable, :polymorphic => true
end
car.rb
class Car < ActiveRecord::Base
has_many :categorizings, :as => :categorizable, inverse_of: :car, dependent: :destroy
has_many :categories, through: :categorizings
end
vendor.rb
class Vendor < ActiveRecord::Base
has_many :categorizings, :as => :categorizable, inverse_of: :vendor, dependent: :destroy
has_many :categories, through: :categorizings
end
cars_controller.rb
class CarsController < ApplicationController
def new
#car = Car.new
end
def create
#car = current_user.cars.build(car_params)
if #car.save
redirect_to #car
else
render 'new'
end
end
private
def car_params
params.require(:car).permit(:name, :details, :type, :category_ids => [] )
end
end
schema.rb
create_table "categories", force: :cascade do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "categorizings", force: :cascade do |t|
t.integer "category_id"
t.integer "categorizable_id"
t.string "categorizable_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "categorizings", ["categorizable_type", "categorizable_id"], name: "index_categorizings_on_categorizable_type_and_categorizable_id", using: :btree
This is what I have in the form
<%= f.collection_select :category_ids, Category.all, :id, :name %>
And I receive this error:
Unpermitted parameter: category_ids
I am very confused right now and lost in models. Dont know this is the best approach or not. I would be glad if someone could tell me where I do the mistake.
Using this select_tag solved my problem
<%= f.select :category_ids, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>
but stops working if I disable multiple like
:multiple => false

Polymorphic association undefined method `build_product'

I am struggling to see what I am doing wrong here..
I have an order model which needs to be able to hold one product, the product needs to be polymorphic.
I have a product/model called orthosis_specification and for some reason I am getting this error when I use it in a fields_for creation.
Migration -
class CreateOrders < ActiveRecord::Migration
def change
create_table :orders do |t|
t.datetime :order_date
t.datetime :date_required
t.boolean :correct
t.references :user, index: true, foreign_key: true
t.references :practitioner, index: true, foreign_key: true
t.references :product, polymorphic: true
t.references :shipping_address, index: true, foreign_key: true
t.references :invoice_address, index: true, foreign_key: true
t.timestamps null: false
end
end
end
Order Controller -
def new
#order = Order.new
#order.build_patient
#order.build_product #Also tried: #order.build_orthosis_specification
end
Order Model -
class Order < ActiveRecord::Base
has_one :patient
belongs_to :product, polymorphic: true
accepts_nested_attributes_for :patient,
reject_if: proc { |attributes| attributes['first_name'].blank? },
allow_destroy: true
accepts_nested_attributes_for :product,
reject_if: proc { |attributes| attributes['transfer_name'].blank? },
allow_destroy: true
def to_s
name
end
end
Orthosis Specification Model -
class OrthosisSpecification < ActiveRecord::Base
has_one :order, :as => :product, class_name: 'Order'
end
Order View -
<%= form_for(#order) do |f| %>
<% if #order.errors.any? %>
<% end %>
<%= f.fields_for :orthosis_specification do |fa| %>
Actual error message -
undefined method `build_orthosis_specification' for #<Order:0x007f8950e29970>
Orthosis Specification Migration -
class CreateOrthosisSpecifications < ActiveRecord::Migration
def change
create_table :orthosis_specifications do |t|
t.string :transfer_name
t.string :modifications
t.string :primary_mods
t.string :top_opening
t.string :side_opening
t.string :chape_position
t.string :scan_file
end
end
end
Any help would be massively appreciated, thanks!
Polymorphic associations don't generate the build_xxx methods. You can create a new product only if you know what kind of product you want to create :
#Creating a new OrthosisSpecification product associated with #order :
#order.product = OrthosisSpecification.new
Documentation : http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Rails join same table two times

I have a table with friendships. It's build like in http://railscasts.com/episodes/163-self-referential-association. Now I want to the most efficient way to get all relations, which are made from both sides (The normal and the inverse friendship).
In MySQL it should look like:
SELECT * FROM Friendship as f1, Friendship as f2 WHERE f1.user_id = f2.friend_id AND f1.friend_id = f2.user_id
In a comment on railscast someone build the extension of the mutual_friends part. But these three lines don't work in my case:
Devise User Model:
class User < ActiveRecord::Base
has_many :features
has_and_belongs_to_many :tags
has_many :friendships
has_many :friends, through: :friendships
has_many :inverse_friendships, class_name: 'Friendship', foreign_key: 'friend_id'
has_many :inverse_friends, through: :inverse_friendships, source: :user
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :first_name, :last_name, :email, :password, :date_of_birth, :gender, :password_confirmation
validates_inclusion_of :gender, :in => ['female', 'male'], message: 'Kein Geschlecht ausgewaehlt'
validates :first_name, presence: true
validates :last_name, presence: true
validates_date :date_of_birth, :on_or_before => lambda { Date.current }
def mutual_friends
inverse_friends.where('user_id in (?)', friend_user_ids)
end
end
Devise User Migration:
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
t.string :reset_password_token
t.datetime :reset_password_sent_at
t.datetime :remember_created_at
t.integer :sign_in_count, :default => 0
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
t.string :first_name
t.string :last_name
t.datetime :date_of_birth
t.string :gender
t.integer :tag_id
t.timestamps
end
add_index :users, :email, :unique => true
add_index :users, :reset_password_token, :unique => true
end
end
Friendship Model
class Friendship < ActiveRecord::Base
attr_accessible :user_id, :friend_id
belongs_to :user
belongs_to :friend, class_name: 'User'
end
Friendship Migration
class CreateFriendships < ActiveRecord::Migration
def self.up
create_table :friendships do |t|
t.integer :user_id
t.integer :friend_id
t.timestamps
end
end
def self.down
drop_table :friendships
end
end
The Error in this solution is:
undefined local variable or method `friend_user_ids' for #<User:0x007fcb93e86de8>
The orginal constellation in the comment on Railscast is:
Friend Model
class Friend < ActiveRecord::Base
belongs_to :profile
belongs_to :friend, :class_name => 'Profile'
end
Profile Model
class Profile < ActiveRecord::Base
has_many :friends
has_many :friend_profiles, :through => :friends, source: :friend
has_many :friended_by, class_name: "Friend" , :foreign_key => "friend_id"
has_many :friended_by_profiles, :through => :friended_by, source: :profile
def mutual_friends
friended_by.where('profile_id in (?)', friend_profile_ids)
end
def mutual_friend_profiles
Profile.where('id in (?)', mutual_friends.pluck(:profile_id))
end
def requesting_friends
friended_by.where('profile_id not in (?)', friend_profile_ids)
end
def requesting_friend_profiles
Profile.where('id in (?)', requesting_friends.pluck(:profile_id))
end
def pending_friends
friends.where('friend_id not in (?)', friended_by_profile_ids)
end
def pending_friend_profiles
Profile.where('id in (?)', pending_friends.pluck(:friend_id))
end
end
Thanks for helping!
The solution how I get it to work:
Remove mutual_friend
def mutual_friends
inverse_friends.where('user_id in (?)', friend_user_ids)
end
Change the logic in the FriendshipController to:
#all mutual friendships with marked true in both relations
#user = current_user
#user_friends = #user.friendships.select{ |friendship| friendship.marked == true }
#user_inverse_friends = #user.inverse_friendships.select{ |friendship| friendship.marked == true }
#friendships = #user_friends.select{ |friend| #user_inverse_friends.map{|inverse_friend| inverse_friend.user_id}.include? friend.friend_id}
#friendships with false mark
#skiped_friendships = current_user.friendships.select { |friendship| friendship.marked != true}
#marked friend: users friendships without the mutual valid friendships
#marked_friends = current_user.friendships - #friendships - #skiped_friendships

Rails has_one and belongs_to migration?

I'm trying to establish a relationship between two models in Rails but I am having trouble figuring out what I need to do in my migration. Any help is much appreciated.
I want each business to have a type/category such as "Automotive", or "Restaurant and Bar".
Business.rb:
class Business < ActiveRecord::Base
has_one :category, :foreign_key => "cid"
attr_accessible :description, :email, :facebook, :foursquare, :google, :manager,
:mobile, :name, :phone, :url, :yelp
end
Type.rb:
class Type < ActiveRecord::Base
attr_accessible :cid, :category
belongs_to :business
end
CreateTypes migration file:
class CreateTypes < ActiveRecord::Migration
def change
create_table :types do |t|
t.integer :cid
t.string :category
t.references :business
t.timestamps
end
add_index :types, :cid
end
end
CreateBusinesses migration file:
class CreateBusinesses < ActiveRecord::Migration
def change
create_table :businesses do |t|
t.string :name
t.string :url
t.string :phone
t.string :manager
t.string :email
t.boolean :mobile
t.boolean :foursquare
t.boolean :facebook
t.boolean :yelp
t.boolean :google
t.text :description
t.integer :cid
t.timestamps
end
end
end
It would be easiest for you to keep with rails naming conventions. If I got it correctly, a business belongs to a Type/Category. let the business reference the type. add a belongs_to on the business side and a has_many on the type/category side. Roughly like this:
class Business < ActiveRecord::Base
attr_accessible :description, :email, :facebook, :foursquare, :google, :manager, :mobile, :name, :phone, :type_id, :url, :yelp
belongs_to :type
end
class Type < ActiveRecord::Base
has_many :businesses
end
class CreateTypes < ActiveRecord::Migration
def change
create_table :types do |t|
t.string :category
t.timestamps
end
end
end
class CreateBusinesses < ActiveRecord::Migration
def change
create_table :businesses do |t|
t.string :name
t.string :url
t.string :phone
t.string :manager
t.string :email
t.boolean :mobile
t.boolean :foursquare
t.boolean :facebook
t.boolean :yelp
t.boolean :google
t.text :description
t.integer :type_id
t.timestamps
end
end
end
Your businesses table must have integer field cid, because it you set it as a foreign key. You types table must not have cid field. The types.id field will be used to create a relationship. Note that belongs_to method doesn't have foreign_key option, you should remove it from its call.
I can advise you not to change foreign key name without a reason. If you don't specify foreign key, it defaults to type_id.

Rename foreign_key to override in Rails Convention

I have a problem in association between two classes, so i have a class table here named Post
Class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :post_type , null: false
t.text :content , null: false
t.integer :person_id
end
add_index :posts, :person_id
add_index :posts, :group_id
end
end
and the other one is called Action
class CreateActions < ActiveRecord::Migration
def change
create_table :actions do |t|
t.string :target_type, null:false
t.integer :target_id
t.integer :upvote_count
t.timestamps
end
add_index :actions,:target_id
end
end
so the problem is i want to associate the target_is as the foreign key to the Post class so i did this
class Post < ActiveRecord::Base
has_one :action
end
class Action < ActiveRecord::Base
belongs_to :post , :class_name => 'Target', :foreign_key => 'target_id'
end
but is doesn't work, which when i assign Action object to action method in Post object this error is appeared
Mysql2::Error: Unknown column 'actions.post_id' in 'where clause': SELECT `actions`.* FROM `actions` WHERE `actions`.`post_id` = 6 LIMIT 1
so any help?
You need to set the foreign key on both sides of the association:
class Post < ActiveRecord::Base
has_one :action, :foreign_key => 'target_id'
end
class Action < ActiveRecord::Base
belongs_to :post , :class_name => 'Target', :foreign_key => 'target_id'
end
http://guides.rubyonrails.org/association_basics.html#has_one-association-reference
http://guides.rubyonrails.org/association_basics.html#belongs_to-association-reference
I suppose you are trying to apply polymorphic association. Try this out.
class Post < ActiveRecord::Base
has_one :action, :as => :target
end
class Action < ActiveRecord::Base
belongs_to :target, :polymorphic => true
end

Resources