Getting ActiveModel::MissingAttributeError: while inserting data using ROR - ruby

I am getting the following error while inserting the data into database through rails console using ROR.
Error:
irb(main):004:0> book.comments << comment
(1.0ms) begin transaction
(0.0ms) rollback transaction
ActiveModel::MissingAttributeError: can't write unknown attribute `book_id`
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4
.2.5.1/lib/active_record/attribute.rb:138:in `with_value_from_database'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4
.2.5.1/lib/active_record/attribute_set.rb:39:in `write_from_user'
from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/activerecord-4
.2.5.1/lib/active_record/attribute_methods/write.rb:74:in `write_attribute_with_
type_cast'
Here I am trying to link one table (comments) with another table (books) by inserting some data. My code flow is below:
irb(main):004:0>book=Book.find(1)
comment = Comment.new :text => "This is an comment", :author => "Adam"
book.comments << comment
.......create_comments.rb:
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.text :text
t.string :author
t.timestamps null: false
end
end
end
book.rb:
class Book < ActiveRecord::Base
has_many :comments
end
comment.rb:
class Comment < ActiveRecord::Base
belongs_to :book
end
While I am executing the last line this error is coming.

You have not book_id column in your comments table.
Follow this below steps:
rails g migration AddBookToComments book:references
which will create a migration file as:
class AddBookToComments < ActiveRecord::Migration
def change
add_reference :comments, :book, index: true, foreign_key: true
end
end
run rake db:migrate
add book_id in strong paremeters in comments_controller.rb
Then try:
> book=Book.find(1)
> comment = book.comments.new(:text => "This is an comment", :author => "Adam")
> comment.save!

Related

Active Record has_many :messages not saving records properly

I'm building a sinatra app with Active record. The idea is to essentially have a custom email app. Here I have the models User and Message. A User has_many :messages and a Message belongs_to :user. This may be where I have the issue. I also have it set up for a Message belongs_to :user and has_many :users.
here are the models
Now when I create a message in the action controller I am attempting to use the shove methods to put the new message in a user's messages array. If I attempt to "share" this message with multiple users at once with all the user's id's in params( #user = User.find(id) and then user.messages << #new_message) the last user will have the message stored in it's .messages array. However only the last one to be iterated.
class Message < ActiveRecord::Base
belongs_to :user
has_many :users
end
class User < ActiveRecord::Base
validates :username, presence: true, uniqueness: true
has_secure_password
has_many :messages
end
The idea is the writer "owns" the message but can share it with many users. Here are the tables
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :username
t.string :email
t.string :password_digest
end
end
end
class CreateMessages < ActiveRecord::Migration
def change
create_table :messages do |t|
t.string :message
t.string :author
t.integer :user_id
t.integer :user_ids
t.integer :share_id
t.string :title
t.timestamps
end
end
end
# action controller
new_params = {}
new_params[:message] = params["message"]
new_params[:title] = params["title"]
new_params[:author] = params["author"]
new_params[:user_id] = params["user_id"]
#message = Message.create(new_params)
# #share = Share.create
# #message.share_id = #share.id
response.map do |x|
x.messages << #message
x.save!
end
#all = User.all
#user = User.find_by(username: #message.author)
erb :"/user/sent"
I am fairly sure this is because my associations are not set up properly.
You need to have has-and-belongs-to-many relationship between users and messages to implement sharing multiple messages to multiple users. Create an additional record, e.g. MessageShare and do has many to it from both sides:
class MessageShare < ActiveRecord::Base
belongs_to :user
belongs_to :message
end
class Message < ActiveRecord::Base
has_many :message_shares
end
class User < ActiveRecord::Base
has_many :message_shares
end
message_shares table should have user_id and message_id integer columns.

Error creating new method of nested resources

I have my resources:
resources :flows do
resources :fmodules
end
the new method in fmodules controller:
# /flows/1/fmodules/new
def new
#flow = Flow.find(params[:flow_id])
#fmodule = #flow.fmodules.build
end
the models:
class Flow < ApplicationRecord
has_many :fmodules, dependent: :destroy
validates :code, presence: true, length: { maximum: 5 }
validates :name, presence: true
end
class Fmodule < ApplicationRecord
belongs_to :flow
end
When i try to go at /flows/1/fmodules/new ruby says unknown attribute 'flow_id' for Fmodule.
I dont know what is wrong
Here is the migration of Fmodel in addition
class CreateFmodules < ActiveRecord::Migration[5.1]
def change
create_table :fmodules do |t|
t.string :code
t.string :name
t.string :f_code
t.timestamps
end
add_foreign_key :fmodules, :flows, column: :f_code
end
end
So, the problem is that you don't have a flow_id in your fmodules table. In rails, by convention the foreign key is build automatically inferring column name from an argument you pass to belongs_to. That's why rails think that foreign key for flows table is flow_id and it raises exception not finding it. You can overwrite the default with foreign_key option like the following
class Fmodule < ApplicationRecord
belongs_to :flow, foreign_key: : f_code
end

ActiveModel::MissingAttributeError: can't write unknown attribute `attendee_id`

I am trying to create an association between a User model and an Attendance model in which an attendee_id references a user. The association is a many to many relationship between users and concerts. The join table attendances has two fields
:attendee and :concert.
seed.rb file:
require 'faker'
Concert.destroy_all
User.destroy_all
Attendance.destroy_all
15.times do
Concert.create(band: Faker::RockBand.name, venue: "#{Faker::LordOfTheRings.location}", date: Faker::Date.forward(rand(30)), start_time: "8:00 PM")
end
5.times do |number|
User.create(first_name: Faker::Name.first_name, last_name: Faker::Name.last_name, email: "#{number}#email.com", password: "password")
end
concerts = Concert.all
users = User.all
15.times do
Attendance.create(attendee: users.sample, concert: concerts.sample)
end
Here are the models:
class Attendance < ApplicationRecord
belongs_to :attendee, class_name: "User"
belongs_to :concert
end
class Concert < ApplicationRecord
validates :band, :venue, :date, :start_time, presence: true
has_many :attendances
has_many :attendees, through: :attendances
end
class User < ApplicationRecord
validates :first_name, :last_name, :email, presence: true
validates_format_of :email, with: /#/
has_secure_password
has_many :attendances, foreign_key: :attendee_id
has_many :concerts, through: :attendances
end
Here are the migrations:
class CreateAttendances < ActiveRecord::Migration[5.0]
def change
create_table :attendances do |t|
t.references :attendee
t.references :concert, index: true
t.timestamps
end
end
end
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.string :password_digest
t.timestamps
end
end
end
class CreateConcerts < ActiveRecord::Migration[5.0]
def change
create_table :concerts do |t|
t.string :band
t.string :venue
t.datetime :date
t.time :start_time
t.timestamps
end
end
end
Looks like there are no attendee_id column
bundle exec rails db:reset (same as db:drop + db:create + db:migrate + db:seed)
And for tests bundle exec rails db:test:prepare
If it`s not solve the problem, i think, we need moar stacktraces)
I run bundle exec rake db:drop and then I created the database bundle exec rake db:create and bundle exec rake db:migrate I was then able to seed the database.
Please try to change t.references to special alias t.belongs_to.
It worked for me with Rails 5.2.1

avoiding destroy with foreign key

I'm new in Ruby on Rails. I don't understand how rails behave using foreign Key, I've researched it for some days but I didn't get the answer.
Simple sample:
I created two tables:
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :title
t.text :content
t.timestamps null: false
end
end
end
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.string :author
t.text :content
t.references :post, index: true, foreign_key: true
t.timestamps null: false
end
end
end
My models are:
class Post < ActiveRecord::Base
has_many :comments
end
class Comments < ActiveRecord::Base
belongs_to :post
end
My doubt is: As I have a Foreign Key in my table COMMENTS (.references :post, index: true, foreign_key: true) I guess that I wouldn't be able to destroy any post which has any COMMENTS associated to them, isn't it ?
I did as above but I am still able to destroy the posts, even when I have the comments associated. How can I treat it? What am I doing wrong?
Cheers
I'd refine your migrations to use the :on_delete options on your foreign keys. It can take one of those values : :nullify, :cascade, :restrict
From what I understand, you need to set this value to :restrict on your post_id column in your comments table, so that posts with associated comments can't be deleted.
Update:
Or, you could also directly set it on the association in your Post model:
has_many :comment, dependent: :restrict_With_error
Please take a look at:
http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many -> See the Options: Section
From what i understand, you dont want to destroy a post if there are associated comments?
Why not put a if statement encapsulating the delete button for a post
So something like:
psudo code
if #post.comments exists
cant delete post
else
delete post
end

How to access other table's attributes using associations

"Hello everyone" I'm practicing a little bit with rails right now and I'm having issues understanding how to access data with associations. Currently I have 3 tables, Doctors, Patients and Appointments.
class CreateDoctors < ActiveRecord::Migration
def change
create_table :doctors do |t|
t.string :name
t.timestamps null: false
end
end
end
class CreatePatients < ActiveRecord::Migration
def change
create_table :patients do |t|
t.string :name
t.timestamps null: false
end
end
end
class CreateAppointments < ActiveRecord::Migration
def change
create_table :appointments do |t|
t.date :date_appointment
t.references :doctor, index: true, foreign_key: true
t.references :patient, index: true, foreign_key: true
t.timestamps null: false
end
end
end
With this I'm trying to create a form to insert record on Appointments table, this way I can access and get the names for either doctors or patients after submitting the form.
<%= form_for(#appointment) do |f| %>
<%= f.label :date, "Choose a date for your appointment" %>
<%= f.collection_select(:doctor_id, Doctor.all, :id, :name, prompt: true) %>
<%= f.submit %>
<% end %>
The data is being inserted, but when I call the Show "Template" is giving me an error saying that the parameter for doctor in "Nil" even though it has a value.
<%= #appointment.doctor.name %>
And here's the appointment controller data
class AppointmentsController < ApplicationController
def index
end
def show
end
def new
#appointment = Appointment.new
end
def create
#appointment = Appointment.new(appointment_params)
if #appointment.save
redirect_to #appointment
else
render "New"
end
end
private
def appointment_params
params.require(:appointment).permit(:date, :doctor_id, :patient_id)
end
def find_appointment
#appointment = Appointment.find(params[:id])
end
end
What I want to do is basically be able to render or show the names of doctors or patients according to the value of the attributes on the row that is being created after creating a new row with the form.
class Appointment < ActiveRecord::Base
belongs_to :doctor
belongs_to :patient
end
class Doctor < ActiveRecord::Base
has_many :appointments
has_many :patients, through: :appointments
end
class Patient < ActiveRecord::Base
has_many :appointments
has_many :doctors, through: :appointments
end
Thank you for your time!
Maybe I'm missing something but aren't you forgetting to set the #appointment var?
def show
#appointment = Appointment.find(params['id'])
end
(should work if you have a route for this)

Resources