Creating and enforcing has_one relationship in rails relational database - ruby-on-rails

Working on a table of viewed profiles. I kind of have an issue setting it up, is this correct? I am confused about the has_many and has_one relationship. Because this is one table that has a row for each visited relationship, I decided to go with has_one.
Does this look correct, also is there a way to enforce the relation in ActiveRecord?
model
class ViewedProfile < ActiveRecord::Base
validates :viewed_profile_id, presence: true
validates :profile_id, presence: true
has_one :profile_id
has_one :viewed_profile_id
end
migration
class CreateViewedProfile < ActiveRecord::Migration
def change
create_table :viewed_profiles do |t|
t.integer :profile_id
t.integer :viewed_profile_id
end
end
end
edit
Also when I go to my console and I type ViewedProfile nothing comes up. Any idea as to why? =c the schema should normally show up!

Firstly, you are confused in between the terms Model names and attributes(specially Foreign keys).Model will have attributes and the associations will be set to models.
You have to set your models like this
class ViewedProfile < ActiveRecord::Base
has_one :profile
end
Class Profile < ActiveRecord::Base
belongs_to :viewed_profile
validates :viewed_profile_id, presence: true
validates :viewed_profile_id, uniqueness: true
end
And your corresponding migration files should look like this
class CreateViewedProfile < ActiveRecord::Migration
def change
create_table :viewed_profiles do |t|
t.string :name
end
end
end
class CreateProfile < ActiveRecord::Migration
def change
create_table :profiles do |t|
t.integer :viewed_profile_id
end
end
end
I would recommend to read these Guides articles before getting started.
Associations
Migrations
Validations

Related

generating migration for a through association

here are the additions that I have made to my models:
class Event < ApplicationRecord
has_one :lineup
has_many :artists, :through => :lineup
belongs_to :venue
end
class Lineup < ApplicationRecord
belongs_to :artist
belongs_to :event
end
class Artist < ApplicationRecord
has_many :events, :through => :lineups
end
class Venue < ApplicationRecord
has_many :events
end
not asking for help with generating migrations for all of these associations, but could you at least show me how to do it for Event?
Please find below migrations for Event & Lineup (that have the keys to enable your model associations):
class CreateEvents < ActiveRecord::Migration
def change
create_table :events do |t|
t.references :venue, index: true, foreign_key: true
t.timestamps null: false
end
end
end
class CreateLineups < ActiveRecord::Migration
def change
create_table :lineups do |t|
t.references :artist, index: true, foreign_key: true
t.references :event, index: true, foreign_key: true
t.timestamps null: false
end
end
end
To generate them, you can use:
rails g migration create_events venue:references
rails g migration create_lineups artist:references event:references
If Event & Lineup already exist, you can generate the migrations as follows:
rails g migration add_reference_to_events venue:references
rails g migration add_references_to_lineups artist:references event:references
Migrations generated should be as follows:
class AddReferenceToEvents < ActiveRecord::Migration
def change
add_reference :events, :venue, index: true, foreign_key: true
end
end
class AddReferencesToLineups < ActiveRecord::Migration
def change
add_reference :lineups, :artist, index: true, foreign_key: true
add_reference :lineups, :event, index: true, foreign_key: true
end
end
belongs_to will place the foreign key in the declaring model whereas has_one will place it in the other model. There are good resources in this out there that I would recommend taking a look at. Here's one.
So for the event model I would do the following:
$ rails g migration AddVenueToEvents
Then fill it in with:
class AddVenueToEvents < ActiveRecord::Migration
def change
add_reference :events, :venue, index: true, foreign_key: true
end
end
I would strongly recommend making use of the something like the Shoulda gem in combination with RSpec as it provides extremely valuable feedback about what you should be doing. Which would allow you to write some specs:
RSpec.describe Events, type: :model do
#Associations
it { should belong_to(:venue) }
it { should have_one(:lineup) }
it { should have_many(:artists).through(:lineup) }
The awesome thing is that once you run the your specs shoulda/rspec will give you extremely useful feedback in the terminal essentially telling you where a required Foreign Key may be missing. The message might look something like this:
Region should have a city
Failure/Error: should belong_to(:city)
Expected Region to have a belongs_to association called city (Region does not have a city_id foreign key.)
# ./spec/models/region_spec.rb:5:in `block (2 levels) in <top (required)>'
as shown in this other SO post which is somewhat related.
Please check this migration for events.
class CreateEvents < ActiveRecord::Migration
def change
create_table :events do |t|
t.belongs_to :venue, index: true
t.timestamps null: false
end
end
end

Understanding Rails Model Associations

I'm relatively new to Ruby on Rails and I'm trying to understand the way how active record associations work. So far, I thought I figured it out, but not sure anymore.
Anyway, I'm building my very own CMS and apart from all, I'll focus on my main problem. I'm having a table pages and pictures:
class CreatePages < ActiveRecord::Migration
def change
create_table :pages do |t|
t.string :name
t.integer :headline_image_id
t.timestamps
end
create_table :pictures do |t|
t.string :name
t.string :description
t.string :image
t.timestamps
end
end
end
With this I have my models:
class Page < ActiveRecord::Base
validates :name, presence: true
validates :headline_image_id, presence: true
belongs_to :headline_image, class_name: Picture, foreign_key: :headline_image_id
end
class Picture < ActiveRecord::Base
mount_uploader :image, ImageUploader
end
And that's it. Now after I create a picture and a page which has the id of a picture in the headline_image_id attribute, I can fetch that headline_image with #target_page.headline_image. Perfect, but the thing that is bothering me is the readability of the code. Wouldn't it make much more sense if I associated the two models in the Page model like this:
class Page < ActiveRecord::Base
validates :name, presence: true
validates :headline_image_id, presence: true
has_one :headline_image, class_name: Picture, foreign_key: :headline_image_id
end
If I do it like this and run #target_page.headline_image I get a SQL Constraint exception that tells me there is no headline_image_id in the pictures table.
I read all the Active Record Association tutorial on Ruby on Rails Guides and watched all the codeschool Rails courses, and I was pretty sure that everything was going to work with a has_one association...but it didn't.
Can someone please explain?
Thanks!
Rails Guides provides an explanation as to why you're experiencing the problem. Essentially, when you declare a belongs_to relationship, the foreign key appears on the table for the class declaring it. When you declare a has_one relationship, the foreign key is on the table for the class in the declaration.
Example
In this scenario, the pictures table would require a page_id foreign key.
class Page < ActiveRecord::Base
has_one :picture
end
class Picture < ActiveRecord::Base
belongs_to :page
end
In this scenario, the pages table would require a picture_id foreign key.
class Page < ActiveRecord::Base
belongs_to :picture
end
class Picture < ActiveRecord::Base
has_one :page
end
If you wanted to use a has_one association, just remove the headline_image_id column from your pages table and add a page_id column to your pictures table. You can do this in one migration. After you run the migration, change your model definitions as per my above example. Hope this helps.

has_one relationship is resulting in ActiveModel::MissingAttributeError , what am I missing here?

I feel like I am overlooking something obvious here. I can create a story model, and a category model, but I can't relate a story to a category.
Here is how I reproduce the error:
s = Story.new(title: "test", picture_url: "www.google.com")
c = Category.last
s.category = c
error: ActiveModel::MissingAttributeError: can't write unknown attribute `story_id'
Story model
class Story < ActiveRecord::Base
has_many :chapters, dependent: :destroy
has_many :users, through: :story_roles
has_one :category
end
Story migration file
class CreateStories < ActiveRecord::Migration
def change
create_table :stories do |t|
t.string :title
t.string :picture_url
t.integer :category_id
t.timestamps
end
end
end
Category model
class Category < ActiveRecord::Base
belongs_to :story
validates_presence_of :body
end
Category migration
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.string :body
t.timestamps
end
end
end
In your story model, change has_one :category to belongs_to :category. A rule of thumb is if you have a foreign key for a model, you declare the association as belongs_to. In this example, you have category_id in the story model so you use belongs_to :category in the story model. This makes perfect sense since a story should really belong to a category and a category has_many stories.
You miss t.references :story in your migration. The belongs_to method on category requires story_id.
class CreateCategories < ActiveRecord::Migration
def change
create_table :categories do |t|
t.references :story
t.string :body
t.timestamps
end
end
end
You are missing a foreign_key story_id in your Category Model. Add that column in your categories table and migrate it.That would resolve your issue.
Note: Before migrating the changes,roll back the previous migration.
OR
The best way is what #bekicot suggested. Just add t.references :story. This includes story_id,so that it will be added to your categories table by default.

Rails adding many to many association?

i have a "Question" model and a "Tag" model. I added a many-to-many association to these two model.
that's what i have now :
class Question < ActiveRecord::Base
attr_accessible :content, :score, :title
has_and_belongs_to_many :tags
end
class Tag < ActiveRecord::Base
attr_accessible :description, :name
has_and_belongs_to_many :questions
end
What should i do to update the database and the controllers ?
thanks
Create a migration for the join table with the following command:
$ rails g migration questions_tags question_id:integer tag_id:integer
Create the table in the database:
$ rake db:migrate
Rails magic will help you populate the join table. I created a many-to-many code quiz with a has_and_belongs_to_many example that you might find helpful.
You can consult with Rails Guide on associations here. Here's a code snippet right from there:
# Models
class Assembly < ActiveRecord::Base
has_and_belongs_to_many :parts
end
class Part < ActiveRecord::Base
has_and_belongs_to_many :assemblies
end
# Corresponding migration for creating models and join table
class CreateAssembliesAndParts < ActiveRecord::Migration
def change
create_table :assemblies do |t|
t.string :name
t.timestamps
end
create_table :parts do |t|
t.string :part_number
t.timestamps
end
create_table :assemblies_parts do |t|
t.belongs_to :assembly
t.belongs_to :part
end
end
end

Creating a database relationship that allows for multiple assignments of the same id

I'm really new to RoR so I apologize if I'm not thinking about this right. I have a Report where I need to be able to assign multiple users to that report. A user can be assigned to more than one report and a report can have multiple users. How do I create the database relationship where this would be allowed. I understand how to assign one user to one report but not many users to a single report.
I'd use a joining class to make this happen:
class Report
has_many :assignments
has_many :users :through => :assignments
end
class User
has_many :assignments
has_many :reports, :through => :assignments
end
class Assignment
belongs_to :report
belongs_to :user
end
The class Assignment has two fields: report_id and user_id to create the relationship.
Read the Ruby on Rails Guide to Active Record Associations: http://guides.rubyonrails.org/association_basics.html
I highly recommend you familiarize yourself with the Ruby on Rails guides. They will prove to be an invaluable asset!! For this task the site would be RailsGuides Active Record Associations.
As far as the code goes you want to create three database tables: reports, reports_users, and users, with reports_users being a join table.
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name, :null => false
t.timestamps
end
end
end
class CreateReports < ActiveRecord::Migration
def change
create_table :reports do |t|
t.string :name, :null => false
t.timestamps
end
end
end
class ReportsUsers < ActiveRecord::Migration
def change
create_table :reports_users, :id => false do |t|
t.references :user, :null => false
t.references :report, :null => false
end
end
end
Once you run this migration you need to set up the active record associations in your models.
class User < ActiveRecord::Base
has_and_belongs_to_many :reports
end
class Report < ActiveRecord::Base
has_and_belongs_to_many :user
end
This will set up the database and the many-to-many models connections. This will get you started. Now you have to go create some views

Resources