Ruby on Rails Has_Many :Through Association - ruby-on-rails-3

I'm having some problems with ruby on rails, specifically setting up a many-to-many connection with deal and event through deal_event. I've checked out several similar stackoverflow questions and even http://guides.rubyonrails.org/ but I'm still not getting something..
Here are my models:
deal.rb
class Deal < ActiveRecord::Base
has_many :deal_events
has_many :events, :through => "deal_events"
attr_accessible :approved, :available, :cents_amount, :dollar_amount, :participants, :type
end
event.rb
class Event < ActiveRecord::Base
has_many :deal_events
has_many :deals, :through => "deal_events"
attr_accessible :day, :image, :description, :location, :title, :venue, :remove_image
end
deal_event.rb
class DealEvent < ActiveRecord::Base
belongs_to :deal
belongs_to :event
end
And here are my migration files:
20130102150011_create_events.rb
class CreateEvents < ActiveRecord::Migration
def change
create_table :events do |t|
t.string :title, :null => false
t.string :venue
t.string :location
t.text :description
t.date :day
t.timestamps
end
end
end
20130112182824_create_deals.rb
class CreateDeals < ActiveRecord::Migration
def change
create_table :deals do |t|
t.integer :dollar_amount
t.integer :cents_amount
t.integer :participants
t.string :type, :default => "Deal"
t.integer :available
t.string :approved
t.timestamps
end
end
end
20130114222309_create_deal_events.rb
class CreateDealEvents < ActiveRecord::Migration
def change
create_table :deal_events do |t|
t.integer :deal_id, :null => false
t.integer :event_id, :null => false
t.timestamps
end
end
end
After I seed my database with one deal and one event, I go into the console and type in
deal = Deal.first # ok
event = Event.first # ok
DealEvent.create(:deal => deal, :event => event) # Error: ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: deal, event
deal.events # Error: ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association "deal_events" in model Deal
Any idea on what I'm doing wrong for these two errors to be popping up? Thanks.

You'll need this line in your DealEvent model:
attr_accessible :deal, :event
Although if it's just a relationship table (which it looks like) then you don't create the relationship that way. Use nested forms and the like.

Related

Change primary and foreign key in ActiveRecord

I have two models :
class Settlement < ActiveRecord::Base
set_primary_key :settlement_identifier
has_many :streets
attr_accessible :city, :name, :service_available, :zip, :country_id,: settlement_identifier
end
class Street < ActiveRecord::Base
belongs_to :settlement, foreign_key: "settlement_identifier"
attr_accessible :name, :settlement_identifier, :street_identifier
end
Because I am doing import for streets and settlements, I need to point streets via settlement_identifier, not settlement_id .
When I do
Street.first.settlement #it compare settlement_identifiers from both tables
But when try to get streets from single settlement like :
Settlement.first.streets
It throws an error
SELECT "streets".* FROM "streets" WHERE "streets"."settlement_id" = 4263
ActiveRecord::StatementInvalid: PG::Error: ERROR: column streets.settlement_id does not exist .
I want that query to be :
SELECT "streets".* FROM "streets" WHERE "streets"."settlement_identifier" = 4263
Any help ?
I solved this problem. Here is solution below :
class CreateSettlements < ActiveRecord::Migration
def change
create_table :settlements, primary_key: :settlement_identifier, id: :false do |t|
t.string :name
t.string :zip
t.string :city
t.string :service_available
t.integer :country_id
t.timestamps
end
end
def down
drop_table :settlements
end
end
Here I set primary_key in my migration to settlement_identifier, and set id to false
Also, my Street migration is:
class CreateStreets < ActiveRecord::Migration
def change
create_table :streets do |t|
t.string :name
t.integer :settlement_identifier
t.string :street_identifier
t.timestamps
end
end
end
So, Street has reference to Settlement via settlement_identifier .
Settlement model :
class Settlement < ActiveRecord::Base
has_many :streets, foreign_key: "settlement_identifier"
attr_accessible :city, :name, :service_available,:settlement_identifier
end
Street model :
class Street < ActiveRecord::Base
belongs_to :settlement, foreign_key: "settlement_identifier"
attr_accessible :name, :settlement_identifier, :street_identifier
end
I tried to set primary_key on Settlement model but that didn't work.
This works fine for me. If anyone have another solution, please put comment or code example.

How to call references to other tables in a model rails

I have a model called cause.rb which has a scope called pesquisa that I want to query in the table causes, fields that are references to other tables. I want to call the table places which have a field called city from the model cause.
Causes table:
class CreateCauses < ActiveRecord::Migration
def change
create_table :causes do |t|
t.string :title, null: false
t.text :description, null: false
t.boolean :anonymous, default: false
t.integer :count_likes, default: 0
t.integer :count_dislikes, default: 0
t.integer :count_visits, default: 0
t.references :user
t.references :category
t.timestamps
end
add_index :causes, :user_id
add_index :causes, :category_id
end
end
class AddPlaceIdToCauses < ActiveRecord::Migration
def change
add_column :causes, :place_id, :integer
end
end
Places table:
class CreatePlaces < ActiveRecord::Migration
def change
create_table :places do |t|
t.string :description
t.decimal :latitude
t.decimal :longitude
t.references :city
t.timestamps
end
add_index :places, :city_id
end
end
Here is the scope:
scope :pesquisa, ->(pesquisa) { where("cause.place.city like :p or category_id like :p ", p: "%#{pesquisa}%") }
default_scope :order => "id desc"
How do I resolve this problem? I try this above cause.place.city to call the city in the table places but nothing happens.

self.votable not assigning values to the votable instance in a model callback?

I have a Post model that has a polymorphic association with a Vote model:
post.rb:
class Post < ActiveRecord::Base
attr_accessible :title, :content, :total_votes
belongs_to :user
has_many :votes, :as => :votable, :dependent => :destroy
end
vote.rb
class Vote < ActiveRecord::Base
belongs_to :votable, :polymorphic => true
belongs_to :user
before_create :update_total
protected
def update_total
self.votable.total_votes ||= 0
self.votable.total_votes += self.polarity
end
end
As you can see in vote.rb I want to accomplish the following:
Each time an instance of Vote is created, I want to update the total_votes column of the votable model instance (in this case an instance of Post).
But nothing happens, when I create a vote for a post with post.votes.create(:polarity => 1), the total_votes column of the post still being nil.
Any suggestions to fix this?
EDIT:
This didn't work either:
class Vote < ActiveRecord::Base
belongs_to :votable, :polymorphic => true
belongs_to :user
before_create :update_total
protected
def update_total
self.votable.total_votes ||= 0
self.votable.total_votes += self.polarity
self.votable.save!
end
end
schema.rb:
create_table "posts", :force => true do |t|
t.string "content"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "title"
t.integer "comments_count", :default => 0, :null => false
t.integer "total_votes"
end
When you create the Vote object, the Post object already exists. You update it, but you don't save it. Try with the following code:
def update_total
self.votable.total_votes ||= 0
self.votable.total_votes += self.polarity
self.votable.save!
end

Polymorphic many-to-many association error in Ruby On Rails 3

I am struggling with a polymorphic many-to-many association in rails 3.
My Article model looks like this:
class Article < ActiveRecord::Base
has_many :article_tags
has_many :people, :through => :article_tags, :source => :taggable, :source_type => :person
end
My ArticleTag model looks like this:
class ArticleTag < ActiveRecord::Base
belongs_to :article
belongs_to :taggable, :polymorphic => true
end
My Person model looks like this:
class Person < ActiveRecord::Base
has_many :article_tags, :as => :taggable
end
Finally, my Organization model looks like this:
class Organization < ActiveRecord::Base
has_many :article_tags, :as => :taggable
end
I have a schema which looks like this:
ActiveRecord::Schema.define(:version => 20110322234836) do
create_table "article_tags", :force => true do |t|
t.integer "taggable_id"
t.string "taggable_type"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "articles", :force => true do |t|
t.string "title"
t.text "content"
t.date "published_on"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "people", :force => true do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "organizations", :force => true do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
end
end
I was hoping that this would allow me to create people and organizations relationships from my articles like this:
Article.create!
Article.first.people.create!
and hopefully to be able to access it the other way afterwards by
Person.first.articles
Unfortunately I get an error when I try to add a person this way:
Article.first.people.create!
NameError: uninitialized constant Article::person
.../base.rb:1199:in `compute_type'
.../reflection.rb:162:in `klass'
.../association_collection.rb:157:in `transaction'
.../has_many_through_association.rb:41:in `create_record'
.../has_many_through_association.rb:13:in `create!
Any help would be very much appreciated I've tried many alternatives but with no success.
I actually just had to some something similar to this recently. It looks like most of your code is right although in mine for the first section I would try changing do this:
class Article < ActiveRecord::Base
has_many :article_tags
has_many :people, :through => :article_tags, :source => :taggable, :source_type => "Person"
end
Also you can't do: Article.first.people.create({:name => "Tim"})
You would have to assign it to a variable first:
article = Article.first
article.people.create({:name => "Tim"})
Let me know if this works for you. I just skimmed through. If it doesn't i can double check my code again and see if there are any other differences.

Give composite primary key in Rails

How can i give composite primary key in Rails without any gem?
My first table in migration file:
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :userid
t.string :name
t.string :address
t.timestamps
end
end
def self.down
drop_table :users
end
end
My second table in migration file:
class CreateProjects < ActiveRecord::Migration
def self.up
create_table :projects do |t|
t.string :title
t.string :description
t.timestamps
end
end
def self.down
drop_table :projects
end
end
In my schema file:
ActiveRecord::Schema.define(:version => 20110222044146) do
create_table "projects", :force => true do |t|
t.string "title"
t.string "description"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", :force => true do |t|
t.string "userid"
t.string "name"
t.string "address"
t.datetime "created_at"
t.datetime "updated_at"
end
end
Now I want to create a table called User_has_project in which I will refer to User and Project that means will have 2 foreign keys.
So I tried like this:
class CreateUser_has_projects < ActiveRecord::Migration
def self.up
create_table :user_has_projects do |t|
t.references :User
t.references :Project
t.boolean :status
t.timestamps
end
end
def self.down
drop_table :users
end
end
Now how can I set combination of user_id and project_id as a primary key in user_has_projects?
It looks like you're trying to specify a many-many relationship between Users and Projects, with an additional field on the relationship itself.
The way you're currently doing isn't the Rails way of doing things - especially with the concept of a composite primary key.
The Rails/ActiveRecord way of doing this sort of relationship modelling is to have a third model that describes the relationship between User and Project. For the sake of example, I'm going to call it an Assignment. All you need to do is re-name your user_has_projects table to assignments like so:
class CreateAssignments < ActiveRecord::Migration
def self.up
create_table :assignments do |t|
t.references :user
t.references :project
t.boolean :status
t.timestamps
end
end
def self.down
drop_table :assignments
end
end
And then, in your model files:
# app/models/user.rb
class User < ActiveRecord::Base
has_many :assignments
has_many :projects, :through => :assignments
end
# app/models/assignment.rb
class Assignment < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
# app/models/project.rb
class Project < ActiveRecord::Base
has_many :assignments
has_many :users, :through => :assignments
end
You can read more about this here: http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association