I'm trying to make a reddit-like website, so I've created a Forum model which should contain posts, hence I also created a Post model which I want to be a Forum child. My code for this idea is:
forum.rb
class Forum < ApplicationRecord
has_many :posts
validates :name, presence: true,
length: { minimum: 2 }
end
post.rb
class Post < ApplicationRecord
validates :title, presence: true,
length: { minimum: 5 }
validates :text, presence: true,
length: { minimum: 5 }
belongs_to :forum
end
The corresponding migrations are:
create_forums.rb
class CreateForums < ActiveRecord::Migration[5.1]
def change
create_table :forums do |t|
t.string :name
t.text :description
t.timestamps
end
end
end
create_posts.rb
class CreatePosts < ActiveRecord::Migration[5.1]
def change
create_table :posts do |t|
t.string :title
t.text :text
t.references :forum, index: true, foreign_key: true
t.timestamps
end
end
end
My problem arise when I try to create a new post given a certain forum. For example, if I run #forum.posts.create(title: "Title", text: "Body") I get ActiveModel::UnknownAttributeError in Posts#new with the description unknown attribute 'forum_id' for Post.
What is going on?
Have you run your migrations after generating them? ( rake db:migrate )
The only way I can get this error to occur in testing is to remove the forum reference/relationship field from the posts table and then try and create a post related to the forum. When the migration is run with the t.references :forum, index: true, foreign_key: true the command runs perfectly for me.
If you added the reference line after running the migration, you could reset your database by running rake db:drop db:create db:migrate and you should be good to go since you have it in the table creation migration file, but it is worth noting that if you want to add or remove columns or modify your database, you should be creating new migrations for this instead of running through the drop/create process.
Have you migrated your db? If no, then rails db:migrate
and then reset your db: rails db:setup
That should fix the issue.
Related
What we want to achieve
I'm doing the association in Rails, I'm associating the Schedule table with the PostItem table, and I'm associating the PostItem with belongs_to in the Schedule table, even if the PostItem_id associated with it in the Schedule table is empty. I would like to be able to save the file. In other words, I don't want to make the association every time; I always need the PostItem_id when I make the association within migration. Is there any way to allow saving even if the associated parent is empty?
Code
Migration File
class CreateSchedules < ActiveRecord::Migration[6.0]
def change
create_table :schedules do |t|
t.string :name
t.string :color
t.integer :start
t.integer :end
t.boolean :timed
t.boolean :long_time
t.integer :postItem_id # I want to save the file even if it is empty.
t.timestamps
end
end
end
Schedule Model
class Schedule < ApplicationRecord
belongs_to :post_item
validates :start, presence: true
validates :end, presence: true
# validates :postItem_id, allow_nill: true, allow_blank: true
end
postItem model
class PostItem < ApplicationRecord
belongs_to :post
has_many :schedules
end
After Rails 5 belongs_to associations are required by default. If you want it to be optional, you can add optional: true.
belongs_to :post_item, optional: true
You can also change this behaviour per model by doing:
self.belongs_to_required_by_default = false
https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#active-record-belongs-to-required-by-default-option
Its not a problem but more like an annoying step which i have to repeat every time i made a mistake. I created a migration which like this:
class CreateSubmissions < ActiveRecord::Migration
def change
create_table :submissions do |t|
t.references :student, index: true, foreign_key: true
t.references :assignment, index: true, foreign_key: true
t.references :question, index: true, foreign_key: true
t.text :code
t.timestamps null: false
end
add_index :submissions, [:student_id, :assignment_id, :question_id], unique: true
end
end
try to rub rake db:migrate and it give me error that index name is too long and more, i change that line to this
add_index :submissions, [:student_id, :assignment_id, :question_id],
unique: true, name: 'index_submissions'
and again try to execute rake db:migrate at that time it give me error that submission_student_index already exists (because the first time it created the table but throw exception while adding index) i tried to rollback so that i can execute whole submissions table and index together but unfortunately it rollback my previous migration (in some cases a previous table or index or column).
For that i have to manually go to the database and drop that submissions table and then execute rake db:migrate to create submissions table along with the all the index and also that previous migration. Its annoying to go back to the database and manually drop the table, i don't know if i am doing something wrong or there is some better way to this.
I have a Hash attribute in my model that uses Postgres hstore extention. The problem is that this attribute is converted to String by Rails4. This prevents me to make basic operations such as .each or .map to treat my hash attribute.
Using the Rails console, the Hash is not converted. Typing:
#device.data
#device.data.class
Gives in Rails console:
{"city"=>"London", "owner_name"=>"John"}
Hash
And in the application itself (using the navigator):
"\"city\"=>\"London\","\"owner_name\"=>\"John\"
String
Do you have any idea?
Update:
Here is the model:
class Device < ActiveRecord::Base
belongs_to :company
has_many :records
validates :name, presence: true
end
And the corresponding migration file:
class CreateDevices < ActiveRecord::Migration
def change
create_table :devices do |t|
t.string :name
t.hstore :data
t.integer :company_id
t.timestamps
end
add_index :devices, :name
end
end
Try deleting your tmp folder and restarting all your servers.
rm -rf tmp/*
I have a Padrino app I am building where I want to use counter_cache. I am using ActiveRecord as my ORM. In my Repository model, I want to keep a count of the number of contributions that are associated with a given repository. Here are the relevant models:
class Repository < ActiveRecord::Base
has_many :contributions, autosave: true
has_many :users, through: :contributions
validates :full_name, presence: true, uniqueness: true
end
class Contribution < ActiveRecord::Base
belongs_to :user
belongs_to :repository, counter_cache: true
end
class User < ActiveRecord::Base
has_many :contributions
has_many :repositories, through: :contributions
validates :username, presence: true, uniqueness: true
end
The schema is as follows:
create_table "contributions", :force => true do |t|
t.integer "user_id"
t.integer "repository_id"
end
create_table "repositories", :force => true do |t|
t.string "full_name"
t.integer "contributions_count", :default => 0
end
create_table "users", :force => true do |t|
t.string "username"
end
I have created a test in Rspec to check to see that the contributions_count is updating properly. However, I cannot get it to pass. Here's the spec:
describe "when a new contribution is created" do
it "updates the counter cache" do
repo = Repository.create(full_name: "sample_repo")
user = User.create(username: "sample_user")
expect {
Contribution.create(user: user, repository: repo)
}.to change {repo.contributions_count }.by(1)
end
end
When I run the spec, I get the following failure:
1) Repository when a new contribution is created updates the counter cache
Failure/Error: expect {
result should have been changed by 1, but was changed by 0
# ./spec/models/repository_spec.rb:43:in `block (3 levels) in <top (required)>'
I have also tried creating Contributions in the console and it is not updating the repository counter_cache. I've tried a bunch of stuff, but can't seem to figure out how to get it to work properly. Any help would be appreciated. Thanks.
I think this is because your repo object isn't being magically updated by Ruby when the Contribution object is being saved to the database. You will need to reload the information from the database:
repo.reload.contributions_count
I've been trying to setup a Single Table Inheritance model in Rails 3 in which the parent class also contains a has_many relationship. Unfortunately I can't get it to work. Here are three classes as an example:
class Article < ActiveRecord::Base
has_many :paragraphs, :dependent => :destroy, :autosave => true
end
class Paragraph < ActiveRecord::Base
belongs_to :article
end
class SportsArticle < Article
end
And here's the migration that would be used to set this up:
class AddTables < ActiveRecord::Migration
def self.up
create_table :articles do |t|
t.string :type, :null => false # for STI
t.string :title, :null => false
t.timestamps
end
create_table :paragraphs do |t|
t.references :article, :null => false
t.timestamps
end
end
def self.down
drop_table :articles
drop_table :paragraphs
end
end
When I set it up this way and I try to create a new SportsArticle, say by doing the following:
SportsArticle.create(:title => "Go Giants")
I always get the following error:
"TypeError: can't convert String into Integer"
I have no idea how to fix this issue and have tried finding a solution online to no avail. Does anybody who has experience with STI models see anything wrong? Here's the link to the documentation on the create method if it will help in diagnosing the problem:
http://api.rubyonrails.org/classes/ActiveRecord/Base.html#method-c-create
Try renaming :type to something else, like :article_type
eg:
t.string :article_type, :null => false # for STI
The error was being caused due to a naming collision. I was using a name for one of my models called "attributes" which was causing the problem. The hint that eventually diagnosed the problem came from the Rails Association Documentation.