No such column, but column exists - ruby-on-rails

I have a problem with a many to many relation. I've set up the relation via a third party called rtimespans.
Just like in the tutorials told:
The timespan-model:
class Timespan < ActiveRecord::Base
validates :name, presence: true
has_many :rtimespans
has_many :subgroups, through: :rtimespans
validates :start_h, presence: true
validates :start_m, presence: true
validates :end_h, presence: true
validates :end_m, presence: true
validate :e_must_be_0_60
validate :e_must_be_0_24
validate :s_must_be_0_60
validate :s_must_be_0_24
validate :e_bigger_s
def e_must_be_0_60
errors.add(:end_m,"must be 0-60") unless 0 < end_m.to_i
errors.add(:end_m,"must be 0-60") unless 60 > end_m.to_i
end
def e_must_be_0_24
errors.add(:end_h,"must be 0-24") unless 0 < end_h.to_i
errors.add(:end_h,"must be 0-24") unless 24 > end_h.to_i
end
def s_must_be_0_60
errors.add(:start_m,"must be 0-60") unless 0 < start_m.to_i
errors.add(:start_m,"must be 0-60") unless start_m.to_i < 60
end
def s_must_be_0_24
errors.add(:start_h,"must be 0-24") unless 0 < start_h.to_i
errors.add(:start_h,"must be 0-24") unless start_h.to_i < 24
end
def e_bigger_s
s=start_h.to_i*60+start_m.to_i
e=end_h.to_i*60+end_m.to_i
errors.add(:end_h,"End must be bigger than start") unless e > s
end
end
The rtimespan-model:
class Rtimespan < ActiveRecord::Base
belongs_to :timespan
belongs_to :subgroup
validates :subgroup, presence: true
validates :subgroup, presence: true
end
And the subgroup-model:
class Subgroup < ActiveRecord::Base
belongs_to :group
has_many :timespans
has_many :memberships
has_many :users, through: :memberships
has_many :translations
has_many :actioncodes, through: :translations
has_many :entries
has_many :rules
validates :name, presence: true, uniqueness: true
validates :group_id, presence: true
has_many :rtimespans
has_many :timespans, through: :rtimespans
end
Anyways, when I want to call something over the relationship, I get this Error.
ActiveRecord::StatementInvalid in Subgroups#show
Showing C:/xampp/htdocs/fluxcapacitor/app/views/subgroups/show.html.erb where line #40 raised:
SQLite3::SQLException: no such column: rtimespans.subgroup_id: SELECT "timespans".* FROM "timespans" INNER JOIN "rtimespans" ON "timespans"."id" = "rtimespans"."timespan_id" WHERE "rtimespans"."subgroup_id" = ?
Can anyone tell me, how to fix this, or at least tell me, where this error comes from?

I would check migrations as the error indicates. To find out if there's a missing column, please check your schema.rb to make sure the column exist

I Suppose the error is due to you mentioned relation to timespans two times in your Subgroup model.
You have defined
has_many :timespans and
has_many :timespans, through: :rtimespans
Please correct it in the model and check.

Found my Error! I have a "double ID":
create_table "rtimespans", force: true do |t|
t.integer "subgroup_id_id"
t.integer "timespan_id_id"
end
I created a wrong migration:
class CreateRtimespans < ActiveRecord::Migration
def change
create_table :rtimespans do |t|
t.belongs_to :subgroup_id
t.belongs_to :timespan_id
end
end
end
It should have been:
class CreateRtimespans < ActiveRecord::Migration
def change
create_table :rtimespans do |t|
t.belongs_to :subgroup
t.belongs_to :timespan
end
end
end

Related

Can't work before_validation when nested field is delated with cocoon gem

I have this migration and model for order and order_detail with cocoon gem.
class CreateOrders < ActiveRecord::Migration[5.0]
def change
create_table :orders do |t|
t.integer :total_price
t.timestamps
end
end
end
class CreateOrderDetails < ActiveRecord::Migration[5.0]
def change
create_table :order_details do |t|
t.integer :subtotal_price
t.integer :unit_price
t.integer :quantity
t.references :order, foreign_key: true
t.timestamps
end
end
end
class Order < ApplicationRecord
has_many :order_details, inverse_of: :order, dependent: :destroy
before_validation :calculate_order_price
accepts_nested_attributes_for :order_details, :reject_if => :all_blank, :allow_destroy => true
def calculate_order_price
order_details.each(&:calculate_order_detail_price)
self.total_price = order_details.map(&:subtotal_price).sum
end
end
class OrderDetail < ApplicationRecord
belongs_to :order
def calculate_order_detail_price
self.subtotal_price = unit_price * quantity
end
end
When I save the record after to add or edit the nested field, it works well. But if I edit to delate nested field, calculate_order_price doesn't work.
If somebody knows about this, please advise me.
There is an option :touch which will make sure upon update the parent sets the updated_at (or other fields) but it will not run the validations. There is however also an option :validate (but not entirely sure it will be called upon destroy):
belongs_to :order, validate: true
Otherwise, if those not work, you could do something like
class OrderDetail < ApplicationRecord
belongs_to :order
after_destroy :trigger_parent_validation
def trigger_parent_validation
if order.present?
order.validate
end
end
end

has_many or belongs_to works wrong

I have this two models:
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question
has_many :edits, dependent: :destroy
end
class Question < ActiveRecord::Base
belongs_to :user
has_many :answers, dependent: :destroy
end
But when I write in rails console following:
q=Question.new
q.save
a=Answer.new
a.question = q
a.save
q.answers.size
It gives me zero.
irb(main):026:0> q.answers.size
=> 0
But when I write this:
Answer.where(:question_id => q.id).size
it gives me 1
SO WHAT DO I DO?
In case you need it - answers and question migrations:
class CreateAnswers < ActiveRecord::Migration
def change
#execute "DROP TABLE #{:answers} CASCADE"
create_table :answers do |t|
t.text :body
t.references :user, index: true, foreign_key: true
t.references :question, index: true, foreign_key: true
t.timestamps null: false
end
end
end
class CreateQuestions < ActiveRecord::Migration
def change
#execute "DROP TABLE #{:questions} CASCADE"
create_table :questions do |t|
t.string :title
t.text :body
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
You need to use inverse_of option in your relationship.
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question, inverse_of: answers
has_many :edits, dependent: :destroy
end
class Question < ActiveRecord::Base
belongs_to :user
has_many :answers, inverse_of: question, dependent: :destroy
end
So when you do:
a.question = q
Rails will do this for you(in memory):
q.answers << a
And you don't need to reload the q again.

Rating with Rails (many_to_many)

I'm trying to build a rating system into my app and currently stuck on the associations and indices. I'm quite new to this so I need all the help I can get...
User model
class User < ActiveRecord::Base
has_many :demos
has_many :ratings
has_many :reviewed, through: :ratings, source: :reviewed'Demo'
That's part of it.
Demo model
class Demo < ActiveRecord::Base
belongs_to :user
belongs_to :subject
has_many :ratings
has_many :reviewers, through: :ratings, source: :reviewer
The subject is irrelevant.
Rating model
class Rating < ActiveRecord::Base
belongs_to :reviewed
belongs_to :reviewer
validates :rating, presence: true, numericality: { :greater_than_or_equal_to => 0, :less_than_or_equal_to => 5}
end
end
And now you can tell I'm not really sure what I'm doing.
Ratings Migration Table
class CreateRatings < ActiveRecord::Migration
def change
create_table :ratings do |t|
t.float :rating, default: 2.5
t.belongs_to :reviewed, index: true
t.belongs_to :reviewer, index: true
t.timestamps null: false
end
end
end
Demos Migration Table
class CreateDemos < ActiveRecord::Migration
def change
create_table :demos do |t|
t.references :user, index: true
t.references :subject, index: true
t.string :name
t.text :content
t.string :materials
t.timestamps null: false
end
add_index :demos, [:user_id, :subject_id, :created_at]
end
end
I haven't built a controller for ratings yet since I'm just testing the relationships using the sandbox console.
I've successfully created a Rating, but #user.reviewed and #user.ratings returns a blank array in the Active Record even though #rating has all the Demo and User ids.

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

Adding data in an has_many association

My project consists of People, Events and Comments.
Users can post comments ( accounts are not necessary ) and can attend events.
I'm using a has_many: through association between the people and events but whatever I try, I can't add people to events.
I don't have a clue how I can select someone and add this person to the event_people table.
The models
class EventPeople < ActiveRecord::Base
belongs_to :event
belongs_to :people
end
class Event < ActiveRecord::Base
validates :title, presence:true, length: {minimum: 3}
validates :date_from, presence:true
validates :date_to, presence:true
validates :time_from, presence:true
validates :time_to, presence:true
has_many :comments, dependent: :destroy
has_many :people, :through => :event_people
has_many :event_people
end
class People < ActiveRecord::Base
validates :name, presence: true
validates :email, presence: true, length: { minimum: 5}
validates :birthdate, presence: true
has_many :comments
has_many :events, :through => :event_people
has_many :event_people
end
show method from the eventcontroller
def show
#event = Event.find(params[:id])
end
the table
create_table "event_people", force: true do |t|
t.integer "event_id"
t.integer "people_id"
t.datetime "created_at"
t.datetime "updated_at"
end
Delete the
has_many :event_people
in your People and Event Class
and your migration should look like:
create_table "event_people" do |t|
t.belongs_to :event
t.belongs_to :people
t.timestamps
end
You can either add them individually as klausinho is suggesting, have a from for EventPeople where you'd add one person at a time.
Or the has_many association will give you the people_ids= method on events. So you can then use collection check boxes
<%= form_for #event do |f| %>
<div class="field">
<%= f.collection_check_boxes(:people_ids, People.order(:name), :id, :name)
</div>
<% end %>
Or you could use a multiple select instead.

Resources