I have several models in a separate folder called jira (instance.rb, generic_field.rb, etc.). They are are all namespaced under JIRA, for example JIRA::Instance < ActiveRecord::Base, JIRA::GenericField < ActiveRecord::Base. Here are the two models:
class JIRA::GenericField < ActiveRecord::Base
self.table_name = "jira_generic_fields"
belongs_to :jira_instance, class_name: JIRA::Instance
end
class JIRA::Instance < ActiveRecord::Base
self.table_name = "jira_instances"
has_many :jira_generic_fields, dependent: :destroy, class_name: JIRA::GenericField
end
The DB schema for the tables:
create_table "jira_generic_fields", force: true do |t|
t.string "jira_id"
t.string "name"
t.integer "jira_instance_id", null: false
end
create_table "jira_instances", force: true do |t|
t.string "jira_link"
t.string "crowd_link"
end
In my rails console i create a JIRA::Instance object and when I try to destroy it I get this:
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'jira_generic_fields.instance_id' in 'where clause': SELECT `jira_generic_fields`.* FROM `jira_generic_fields` WHERE `jira_generic_fields`.`instance_id` = 1
Why does ActiveRecord use jira_generic_fields.instance_id instead of jira_generic_fields.jira_instance_id and how can I fix this while keeping the models under the same JIRA namespace?
In the end specifying the foreign_key in the models solved this ...
class JIRA::GenericField < ActiveRecord::Base
self.table_name = "jira_generic_fields"
belongs_to :jira_instance, foreign_key: 'jira_instance_id', class_name: JIRA::Instance
end
class JIRA::Instance < ActiveRecord::Base
self.table_name = "jira_instances"
has_many :jira_generic_fields, dependent: :destroy, foreign_key: 'jira_instance_id', class_name: JIRA::GenericField
end
I don't really like it but it will have to do for now.
Related
Question how can i filter my get api function using the ID ni my URI pattern
for example if the client side uses the localhost:3000/users/1/projects
he will get the projects with a field of "user_id" equal to the URI pattern /users/:id
#routes
resources :users do
resourcers :projects
end
#project controller
def index
#projects = Project.all
render json: #projects
end
#users assocciation
has_many :projects, dependent: :destroy
has_many :tasks, dependent: :destroy
has_many :comments, dependent: :destroy
#project association
class Project < ActiveRecord::Base
has_many :task, dependent: :destroy
belongs_to :user
end
#DB schema
create_table "projects", force: :cascade do |t|
t.string "name"
t.text "descriptions"
t.date "startDate"
t.date "dueDate"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.boolean "project_confirmation"
end
what we want is when the client side uses this route /users/:user_id/projects(.:format) he accepts projects with field of user_id similar to the routes /users/:id
Use AMS or Jbuilder for that.
https://github.com/rails-api/active_model_serializers
https://github.com/rails/jbuilder
I have a person model that i want to connect to multiple addresses (main_address, work_address etc.)
In app/models/person.rb:
class Person < ActiveRecord::Base
belongs_to :main_address, class_name: :Address, foreign_key: :main_address_id
belongs_to :work_address, class_name: :Address, foreign_key: :work_address_id
belongs_to :invoice_address, class_name: :Address, foreign_key: :invoice_address_id
belongs_to :further_address, class_name: :Address, foreign_key: :further_address_id
end
And an address model:
class Address < ActiveRecord::Base
belongs_to :person
end
address migration:
class CreateAddresses < ActiveRecord::Migration
def change
create_table :addresses do |t|
t.string :street
t.string :zip
t.string :city
t.string :country
t.string :lockbox
t.string :type
t.references :person, index: true, foreign_key: true
t.timestamps null: false
end
end
end
app/models/main_address.rb:
class MainAddress < Address
end
When i try to save an address in rails console (the person with id 1 was already created):
2.2.1 (main):0 > main_address = Address.create(type: "main_address", street: "Schumannstr.15", zip: "D-53113", city: "Bonn", country: "Germany", person_id: 1)
I get the error:
ActiveRecord::SubclassNotFound: Invalid single-table inheritance type: main_address is not a subclass of Address
What am i doing wrong?
I think there may be a problem with your belongs_to associations. It seems to me that an address belong to a person, and a person has many addresses. If conceptually this does not represent your requirements then the rest of this answer will need to be adapted.
Also, in the original example you are specifying foreign keys that don't exist as columns in the addresses table. Each address will just be referred to through its id and type pair.
I would expect this type of code to work:
# app/models/person.rb
class Person < ActiveRecord::Base
has_many :addresses
end
# app/models/address.rb
class Address < ActiveRecord::Base
belongs_to :person
end
# app/models/main_address.rb
class MainAddress < Address
end
The type column in your table should trigger STI, allowing you to do something like:
person = Person.create(...)
person.addresses.create(street: "Schumannstr.15", zip: "D-53113", city: "Bonn", country: "Germany")
Hopefully this will work for you. If not, feel free to edit or comment as needed.
It has been a while since I asked something around here.
Since I have just started playing around with Ruby, and can't get my head around this, I decided to come back here for some guidance.
I've read quite a few examples now, but I don't find a proper path to walk to solve this problem.
The idea is the following :
You have :
A family
A person
Their relationship is the following :
There is one person that is the 'head' of the family
Every person is part of a family (be it with multiple persons or just himself in it)
Now the current validation probably makes it impossible to perform this, but the idea is that there is no such thing as a family without a head, and no person without a family.
I've tried to express it the following way :
Family class
class Family < ActiveRecord::Base
validates :head_id, presence: true
belongs_to :head, :class_name => Person, foreign_key: 'head_id'
has_many :persons
end
Person class
class Person < ActiveRecord::Base
validates :family_id, presence: true
validates :first_name, presence: true
belongs_to :family
end
Would any soul be so kind to offer me some advice?
The migration has a family_id on the Person-class side, the family consists of an extra column being person_id.
Family migration
class CreateFamilies < ActiveRecord::Migration
def change
create_table :families do |t|
t.integer :head_id
t.timestamps null: false
end
end
end
Person migration
class CreatePersons < ActiveRecord::Migration
def change
create_table :persons do |t|
t.string :first_name
t.string :last_name
t.integer :age
t.integer :family_id
t.timestamps null: false
end
end
end
You got a circular dependency here. You cannot create families nor people.
Circular dependency usually indicates that there's a third element missing.
More eloquently and not completely related .
There are two kind of membership, head and non-head. Once your make them obvious in your code the circular dependency will be solved.
There a few solutions but you need to find the one fits you the best. This is mine.
Create a membership join table
class Family
validates :memberships, presence: true, on: :update
has_many :memberships
has_many :people, through: :membership
after_create :create_head_membership
private
def create_head_membership
memberships.create role: 'head' # to be filled later
end
end
class Membership
belongs_to :family
belongs_to :person
end
class Person
has_many :memberships
has_one :family, through: :membership # has_many, amrite?
validates :memberships, presence: true, on: :update
end
The most important thing is avoid Person/Family direct manipulation, rather create something to handle this process and wrap it in a transaction
class God
def make_family head_attrs
fam, head = nil
Family.transaction do
fam = Family.create!
head = Person.create! head_attrs
fam.memberships.first.update_attribute! :person_id, head.id
end
fam
end
end
I am not sure if I properly understand your code, but please tell me what is a Publisher class? I think you should do it in this way:
Family model:
has_many :persons
has_one :head, :class_name => Person, foreign_key: 'head_id'
validates :head_id, presence: true
Person model:
belongs_to :family
validates :family_id, presence: true
validates :first_name, presence: true
Family has many persons and has one head. The person belongs to family and it doesn't matter for the person if it's the head of family or not.
Other things like migrations and validations still the same.
Is better validate presence of :head that not head_id
class Family < ActiveRecord::Base
validates :head, presence: true
belongs_to :head, :class_name => Person, foreign_key: 'head_id'
has_many :persons
end
Person have two relations with Family, one if is head and another if is part of a family, you have to validate (as I put in the example) how you can handle this relationships.
class Person < ActiveRecord::Base
validates :family, presence: true
validates :first_name, presence: true
belongs_to :family
belongs_to :head, :class_name => 'Family', :foreign_key => 'head_id'
validate :family_id_is_equal_to_head_id
def family_id_is_equal_to_head_id
self.family = self.head
end
end
Finally migrations are wrong, must define the relantionship
class CreateFamilies < ActiveRecord::Migration
def change
create_table :families do |t|
t.integer :head_id
t.timestamps null: false
end
end
end
class CreatePersons < ActiveRecord::Migration
def change
create_table :persons do |t|
t.string :first_name
t.string :last_name
t.integer :age
t.belongs_to :family
t.integer :head_family_id
t.timestamps null: false
end
end
end
Let's say you have a polymorphic relationship like this:
class Picture < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
end
class Employee < ActiveRecord::Base
has_many :pretty_pictures, as: :imageable
end
class ProductInvoice < ActiveRecord::Base
has_many :pretty_pictures, as: :imageable
end
And this is your migration for the Picture model:
class CreatePictures < ActiveRecord::Migration
def change
create_table :pictures do |t|
t.string :name
t.references :imageable, polymorphic: true
t.timestamps
end
end
end
Let's say you have a #product_invoice with an :id of 1 and you have a #picture that belongs to this product. I know that #picture.imagable_id should equal 1, but what the value stored in #picture.imagable_type be?
'ProductInvoice'
'ProductInvoices'
'product_invoice'
'product_invoices'
via G.B in comments
'ProductInvoice'
right now im building a form that accepts a many to many using a select multiple. after creating the form, im trying to display the information collected in the SHOW page however i dont know how to display that data in embedded ruby. join model is CardTypesList
Models
class Card < ActiveRecord::Base
self.inheritance_column = nil
validates :name, presence: true, uniqueness: {case_sensitive: false}
has_many :card_type_lists
has_many :card_types, through: :card_type_lists
accepts_nested_attributes_for :card_type_lists
end
class CardType < ActiveRecord::Base
has_many :card_type_lists
has_many :cards, through: :card_type_lists
end
class CardTypeList < ActiveRecord::Base
belongs_to :cards
belongs_to :card_types
accepts_nested_attributes_for :card_type
end
NEW form using select
<%= f.label :types %>
<%= f.select :card_type_ids, CardTypes.all.collect{|x| [x.name, x.name]}, {},{:title => "Select a Type", :multiple => true, :class => 'selList'} %>
Embedded ruby trials
<td class="card-td"><%= #card.card_types %></td>
Expected: ["Type 1", "Type2"]
this renders the page, but yields (in text):
<ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_CardTypes:0x00000102f58a18>
EDIT: schema added.
ActiveRecord::Schema.define(version: 20140120042152) do
create_table "card_type_lists", force: true do |t|
t.integer "card_type_id"
t.integer "card_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "card_types", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "cards", force: true do |t|
t.string "name"
t.string "set"
t.string "card_types"
t.string "colors"
t.string "cost"
t.string "rarity"
t.string "oracle"
t.float "value"
t.integer "number_owned"
t.string "notes"
t.string "img_link"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "types_mask"
end
add_index "cards", ["name"], name: "index_cards_on_name", unique: true
end
and this is my controller:
class CardsController < ApplicationController
def new
#card = Card.new
#card.card_type_lists.build.build_card_type
end
def show
#card = Card.find(params[:id])
end
def create
#card = Card.new(card_params)
if #card.save
redirect_to #card
else
render 'new'
end
end
private
def card_params
params.require(:card).permit(:name, :set, {:card_types => []}, :color, :cost, :rarity,:oracle,:value, :number_owned,:notes)
end
end
Should be:
class CardTypeList < ActiveRecord::Base
belongs_to :card
belongs_to :card_type #Singular
end
Some more things to think about:
Does your join model have the correct columns?
You should use accepts_nested_attributes_for
Look at how you're calling the data
Schema
Join models in has_many :through have to have foreign_key references to both models they're joining. The way you do this is to use a schema like this:
card_types_lists
id | card_id | card_type_id | other | information | created_at | updated_at
When you mentioned the error no such column: card_type_lists.card_types_id, it generally means you either don't have the correct column in the db, or your reference is incorrect. Looking at it, it's your association (referencing plural instead of singular)(fixed above)
Forms
Something you should consider is using accepts_nested_attributes_for to send the correct data to the nested models
This is when you want to create some records in either model, and works by allowing you to define "new" objects for your other models in your parent model, passing the data to your child models, like this:
#app/models/card.rb
Class Card < ActiveRecord::Base
has_many :card_type_lists
has_many :card_types, through: :card_type_lists
accepts_nested_attributes_for :card_type_lists
end
#app/models/card_type_list.rb
Class CardTypeList < ActiveRecord::Base
belongs_to :card
belongs_to :card_type
accepts_nested_attributes_for :card_type
end
#app/controllers/cards_controller.rb
def new
#card = Card.new
#card.card_types_lists.build.build_card_type
end
Data
If you want to show your associative data correctly, you should try this:
#app/views/cards/show.html.erb
<%= #card.card_types %>