Rails one to many through a relationship table - ruby-on-rails

I have a Company that has many Users through a join table company_user. Each user should work for only one Company. This is a 1 to many relationship.
I have looked around for this and found the solution in https://stackoverflow.com/a/7080017/883102
But I get the error
PG::UndefinedTable: ERROR: relation "companies" does not exist
LINE 5: WHERE a.attrelid = '"companies"'::regclass
When I try to create a Company. How can I solve this?
My models are
Company
class Company < ActiveRecord::Base
has_many :employments
has_many :users, :through => :employments
end
Users
class User < ActiveRecord::Base
...
end
Employment
class Employment < ActiveRecord::Base
belongs_to :company
belongs_to :user
end
The migration for my join table is
create_table :employment do |t|
t.belongs_to :company
t.belongs_to :user
t.timestamps
end
My schema.rb
create_table "company", force: true do |t|
t.integer "rating"
t.integer "phone"
t.string "name"
t.string "address"
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "employment", id: false, force: true do |t|
t.integer "company_id"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", force: true do |t|
t.string "name"
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
t.string "password_digest"
t.string "remember_token"
t.string "role"
end

Hi I found the answer here
https://stackoverflow.com/a/24318236/883102
The problem was that my table names were in the singular form, I changed these in the migration and then re-created the database. It all seems to be working fine now.
My User class ended up as
class User < ActiveRecord::Base
has_one :employment
has_one :company, :through => :employment
end
This was to allow bi-directional associations

Related

Rails 5 inverse of not working

I'm trying to return JSON API where a show action will
render json: user, include [:books, :friends, :comments]
Problem is, if I try to use the inverse_of in my User and Book model classes like this:
User Serializer
class UserSerializer < ActiveModel::Serializer
...
has_many :friends
has_many :books, inverse_of: :author
...
end
Book Serializer
class BookSerializer < ActiveModel::Serializer
...
belongs_to :author, class_name: "User", inverse_of: :books
...
end
I get an error:
ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: books.user_id: SELECT "books".* FROM "books" WHERE "books"."user_id" = ?):
If I remove the inverse_of and has_many from my User serializer, then I don't get any errors, but then the JSON being returned does not contain the included association.
Likewise, the same happens between Comment and User models.
Am I doing something wrong ?
My DB Schema for my two models are:
User Schema
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "username"
t.string "email"
t.string "password_digest"
t.boolean "banned"
t.integer "role_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "photo"
t.boolean "email_confirmed", default: false
t.string "confirm_token"
t.string "password_reset_token"
t.boolean "show_private_info", default: false
t.boolean "show_contact_info", default: false
t.index ["role_id"], name: "index_users_on_role_id"
end
Book Schema
create_table "books", force: :cascade do |t|
t.string "title"
t.boolean "adult_content"
t.integer "author_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "published"
t.string "cover"
t.text "blurb"
t.index ["author_id"], name: "index_books_on_author_id"
end
When I went to generate my Book model with:
rails generate model books ... author:references
It created this migration file:
class CreateBooks < ActiveRecord::Migration[5.0]
def change
create_table :books do |t|
t.string :title
t.boolean :adult_content
t.references :author, foreign_key: true
t.timestamps
end
end
end
I assume that includes the necessary foreign key setup...
Try to change this line in your User model(user.rb):
has_many :books, inverse_of: :author
to
has_many :books, inverse_of: :author, foreign_key: :author_id
You need to tell rails what foreign_key you used if it's not the default one.And the association should be declared in your models, not serializers. In serializer you are adding keys by "has_many", inverse_of does't works here.

Rails Polymorphic has_one throwing uninitialized constant

In Rails 4 I am trying to setup a polymorphic relationship where I have an address model and multiple other models will have one address. I have the following code:
class Address < ActiveRecord::Base
belongs_to :addressable, polymorphic: true
end
class Corporate < ActiveRecord::Base
has_one :addressable
accepts_nested_attributes_for :addressable
end
In my DB, I have the following:
create_table "addresses", force: true do |t|
t.string "line1"
t.string "line2"
t.string "city"
t.string "zip_code"
t.string "contact_person"
t.string "contact_number"
t.integer "addressable_id"
t.string "addressable_type"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "corporates", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
end
However, when I do
#corporate = Corporate.new
#corporate.build_addressable
I get the following error:
NameError (uninitialized constant Corporate::Addressable)
Any idea what the issue is. I followed the rails guide, which had an example of has_many, while I used has_one.
Probably, should be:
class Corporate < ActiveRecord::Base
has_one :address, as: :addressable
end

Validating the presence of a column on a join model

I think this is a fairly common issue but I couldn't find a solution. My domain has two models, Company and ExternalLink (a representation of a social media provider like Facebook or Twitter). The join model, CompaniesExternalLink, has the direct URL to a social media account (ie http://www.facebook.com/goldmansachs). I need to validate the presence of that URL, but the join is created on the association, which breaks and returns ActiveRecord::RecordInvalid
Any advice would be great. Sample code below:
class Company < ActiveRecord::Base
has_many :companies_external_links
has_many :external_links, through: :companies_external_links, dependent: :destroy
end
class ExternalLink < ActiveRecord::Base
has_many :companies_external_links
has_many :companies, through: :companies_external_links, dependent: :destroy
end
class CompaniesExternalLink < ActiveRecord::Base
validates :url, presence: true
belongs_to :company
belongs_to :external_link
validates :external_link, uniqueness: {scope: :company_id}
end
The relevant parts of the schema.rb
create_table "companies", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
t.string "state"
t.string "logo"
t.string "slug"
t.text "description"
end
create_table "companies_external_links", force: true do |t|
t.integer "company_id"
t.integer "external_link_id"
t.string "url"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "external_links", force: true do |t|
t.string "source"
t.datetime "created_at"
t.datetime "updated_at"
t.string "icon"
end

Which relationship is good to use STI or Polymorphism?

I have read about them but still not clear to me which one I suppose to use and how.
I have User model, Message model and Place model
Message model:
class Message < ActiveRecord::Base
belongs_to :user
end
Messages Table:
create_table "messages", force: true do |t|
t.string "title"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
User model:
class User < ActiveRecord::Base
has_many :messages
end
Users Table:
create_table "users", force: true do |t|
t.string "email"
t.string "password_digest"
t.datetime "created_at"
t.datetime "updated_at"
t.string "username"
end
Now, what I want to do is:
"USER" says "MESSAGES" from "PLACES"
eg. "AHMED" says "HELLO" from "EARTH"
For me both Models (Message and Place) have same data (data type) and same behaviours. So places table should be:
create_table "places", force: true do |t|
t.string "name"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
Now may be I'm confused or making big deal than it should be.
What kind of relation should Message and Place have? should it be STI or Polymorphism?
How should I decide?
I'd appreciate the thinking process of how and why I decide specific association.
This example, despite Messages and Places having the same data, doesn't seems a STI/Polymorphism scenario and they should have two different tables.
This could work as a solution:
create_table "users" do |t|
t.string "username"
end
create_table "messages" do |t|
t.string "text"
t.integer "user_id"
t.integer "place_id"
end
create_table "places" do |t|
t.string "name"
end
class User < ActiveRecord::Base
has_many :messages
has_many :places, through: :messages
end
class Place < ActiveRecord::Base
end
class Message < ActiveRecord::Base
belongs_to :user
belongs_to :place
def to_s
"#{user.username} says #{title} from #{place.name}"
end
end
ahmed = User.new(username: "AHMED")
earth = Place.new(name: "EARTH")
message = Message.new(text: "HELLO", user: ahmed, place: earth)
puts message
# => "AHMED says HELLO from EARTH"

TypeError Conversion on has_many relationship

I have a couple of objects in a Rails app ("Ticket", and "Comment")
class Ticket < ActiveRecord::Base
has_many :attributes
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :ticket
belongs_to :user
end
with the following schema:
create_table "comments", :force => true do |t|
t.integer "ticket_id"
t.integer "user_id"
t.text "content"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "tickets", :force => true do |t|
t.integer "site_id"
t.integer "status"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
However, for some reason - whenever I do a #lead.comments I get a crash:
can't convert String into Integer
Any ideas? This is driving me nuts!
I think the line that's causing you pronlems is:
has_many :attributes
"attributes" is a special word in an Active Record. It refers to the values of the columns in the db.
If you try and override this with an association, then you will have problems.
My suggestion is that you should not have a model called an "attribute" - call it something else, eg "properties", and the problems will go away.

Resources