Undefined method error when using "has_many :through" relationship on Rails3 - activerecord

I am working on a small Android project with RoR server.
Here are the three models:
class User < ActiveRecord::Base
has_many :relations
has_many :friends, :through => :relations
attr_accessor :friend_ids
end
class Relation < ActiveRecord::Base
belongs_to :user
belongs_to :friend
end
class Friend < ActiveRecord::Base
has_many :relations
has_many :users, :through => :relations
end
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :user_name
t.string :password
t.integer :city_id
t.integer :travelstyle_id
t.boolean :online
t.string :self_description
t.string :sex
t.integer :head_id
t.timestamps
end
end
def self.down
drop_table :users
end
end
class CreateFriends < ActiveRecord::Migration
def self.up
create_table :friends do |t|
t.string :user_name
t.integer :city_id
t.integer :travelstyle_id
t.string :self_description
t.string :sex
t.integer :head_id
t.timestamps
end
end
class CreateRelations < ActiveRecord::Migration
def self.up
create_table :relations do |t|
t.integer :user_id
t.integer :friend_id
t.timestamps
end
end
Model User uses model Relation to connect with model Friend. I use scaffold to creat the three models and add the relationship code in their model files. I also create a API controller to send xml file to Android application. Here is the controller code:
def find_friend
#user=User.where("id=?",params[:id])
#friend=#user.friends
respond_to do |format|
format.html
format.xml
end
end
Here is the problem, when I use the api(type in http://localhost:3000/api/find_friend/1.xml), the server throws a mistake:
NoMethodError in ApiController#find_friend
undefined method `friends' for #<ActiveRecord::Relation:0x3478a28>
app/controllers/api_controller.rb:21:in `find_friend'
I am new to Rails and have no idea where the wrong is. Do I have to add something in the "route.rb" or change the migration file?
In the rails console mode, I type in "user=User.find(1), friend=user.friends" and get the correct result.

~~~~(>_<)~~~~
The problem is the controller method "#user=User.where("id=?",params[:id])". The "where" method can not tell whether the result is an array or actually one object. If I use "#user=User.find(params[:id])", rails will be "smart enough" to know that "Oh, yes, this is just one object and it has a method called Friends because someone connects the two models together".
Learning Rails likes a marriage, you think you know well about her but sometimes you think "God actually I know nothing about the mysterious guy."

Related

Trying to make associations with Rails

i'm learning Rails and i'm doing an exercise to practice associations and migration files.
Currently, trying to make a models between users, auction item, and bids.
So far for the migrate files I have the following:
class CreateItem < ActiveRecord::Migration
def change
create_table :auction do |t|
t.string :item_name
t.string :condition
t.date :start_date
t.date :end_date
t.text :description
t.timestamps
end
end
end
class CreateBids < ActiveRecord::Migration
def change
create_table :bids do |t|
t.integer :user_id
t.integer :auction_id
t.timestamps
end
end
end
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email
t.string :username
t.string :password_digest
t.timestamps
end
end
end
These are the following models:
class Bid < ActiveRecord::Base
belongs_to :bidder, class_name: "User", foreign_key: "bidder_id"
belongs_to :auction
end
class User < ActiveRecord::Base
has_many :bids
has_many :auctions, :foreign_key => 'bidder_id'
has_secure_password
end
class Auction < ActiveRecord::Base
belongs_to :seller, class_name: "User", foreign_key: :user_id
has_many :bids
has_many :bidders, through: :bids
end
Any suggestions or opinions? I'm currently trying to test the tables but auctions doesn't seem to be working...
Specifically, my auction table can't seem to find a user_id and therefore a user doesn't have any auctions.
foreign_key refers to the _id (by default) or any unique attribute used to associate the models.
I can't see bidder model, you need to replace them with user_id as they are associated to user model.
Refer for more details belongs_to
class CreateBids < ActiveRecord::Migration
def change
create_table :bids do |t|
t.integer :user_id **do not think this is correct**
t.integer :auction_id **or this one**
t.timestamps
end
end
end
You want to use something more along the lines of the following
class CreateGames < ActiveRecord::Migration[5.0]
def change
create_table :games do |t|
t.integer :total_time
t.references :version, foreign_key: true **#this is how a foreign key should be declared**
t.integer :total_points
t.timestamps
end
end
end
Alternatively, if you want to change things in future migrations you can always add a reference:
def change
add_reference :levels, :version, foreign_key: true
end

Rails Associations: with self through second model

I have two models Classification and ClassificationRelationships. I want to create a hierarchy of classifications using supperclass and subclass so that each classification can have many subclasses but only one superclass.
my migrations look like this
class CreateClassifications < ActiveRecord::Migration[5.0]
def change
create_table :classifications do |t|
t.string :symbol
t.string :title
t.integer :level
t.timestamps
end
add_index :classifications, :symbol
add_index :classifications, :level
end
end
class CreateClassificationRelationships < ActiveRecord::Migration[5.0]
def change
create_table :classification_relationships do |t|
t.integer :superclass_id
t.integer :subclass_id
t.timestamps
end
add_index :classification_relationships, :superclass_id
add_index :classification_relationships, :subclass_id
add_index :classification_relationships, [:superclass_id, :subclass_id], unique: true, name: 'unique_relationship'
end
end
so far with my models I have
class ClassificationRelationship < ApplicationRecord
belongs_to :superclass, :class_name => "Classification"
belongs_to :subclass, :class_name => "Classification"
end
class Classification < ApplicationRecord
has_many :classification_relationships
has_many :subclasses, through => :classification_relationships
has_one :superclass, through => :classification_relationships
end
I read quite a few other posts but am still unsure how to finish the associations. I am pretty sure I need to specify the foreign keys but am not clear on how I should do that. Thanks for the help!
Get rid of ClassificationRelationship.
All you need is for Classification to have a parent_id which, in the root instances, is allowed to be null.
Add:
belongs_to :parent, class_name: 'Classification', foreign_key: :parent_id
def children
Classification.where(:parent_id => self.id)
end
Some operations will not be optimal. e.g. Find all descendants. That's because this will require repeated queries to find children, their children, etc...
This may not be a concern for you.
If it is, I recommend storing a path as such:
after_create :set_path
def set_path
path = parent ? "#{parent.path}#{self.id}/" : "#{self.id}/"
self.update_attributes!(:path => path)
end
Then you can do things like:
def descendants
Classification.where("classifications.path LIKE '#{self.path}%' AND classifications.path <> '#{self.path}'")
end
Of course, make sure path is indexed if you'll be doing queries like that.

Sinatra ActiveRecord Model Problems

So I'm writing my first Sinatra app, and using ActiveRecord as ORM.
so in my app.rb, I have a
class User < ActiveRecord::Base
validates_uniqueness_of :username
validates_presence_of :username
end
and create a migration and ran rake db:migrate on this
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :username
t.string :email
t.string :password
t.string :name
t.float :rating
t.timestamps
end
end
end
However, when in one of my methods I run
post "/create" do
u = User.new
u.save
redirect '/'
end
Sinatra crashes on the User.new and says
No GET data. on it. I've looked at tutorials and have no idea.
I figured it out.
I declared the User class before the function so it didn't see the class.

Rails 4 Active record circular dependency error

These are my tables:
create_table :messages do |t|
t.integer :type
t.string :text
t.datetime :sent_date
t.string :sender
t.timestamps
end
create_table :users do |t|
t.integer :phone
t.string :fullname
t.string :profile_image
t.timestamps
end
create_table :send_tos do |t|
t.string :receiver
t.belongs_to :message
t.boolean :is_received
end
and these are the model classes:
class User < ActiveRecord::Base
has_many :send_tos, :foreign_key => 'receiver'
has_many :messages, :foreign_key => 'sender'
end
class Message < ActiveRecord::Base
belongs_to :user, :foreign_key => 'sender'
has_many :send_tos
end
class Send_to < ActiveRecord::Base
belongs_to :user, :foreign_key => "receiver"
belongs_to :message
end
When I run these commands on rails console:
m = Message.new
m.save
s = Send_to.new
s.message = m
s.save
m.send_tos
After command m.send_tos I get this error:
RuntimeError: Circular dependency detected while autoloading constant
SendTo
Why am I getting this error? What should I do to change it?
Change the name of the Send_to class to SendTo. This follows the naming convention that Rails assumes for its relationships. The name of the file it is in should be send_to.rb

ruby on rails : how to bring changes on database to model

I have update migrate script under db/migrate, and I did a
rake db:migrate
database script before update
class CreateStudents < ActiveRecord::Migration
def change
create_table :students do |t|
t.string :firstname
t.string :lastname
t.string :account
t.timestamps
end
end
end
databse script after update
class CreateStudents < ActiveRecord::Migration
def change
create_table :students do |t|
t.string :firstname
t.string :lastname
t.string :account
t.string :address
t.string :city
t.string :state
t.string :postcode
t.string :homephone
t.timestamps
end
end
end
after I dropped the old development.sqlite3 and old schema in schame.rb.
Say I added a few columns, but in the model these columns is missing.
But my model still is
class Student < ActiveRecord::Base
attr_accessible :firstname,:lastname,:account,
end
Is there a easy way I can bring the changes in new migrate script to model ?
If you want to allow for mass assignments of the other attributes, you can just add the keys to attr_accessible
class Student < ActiveRecord::Base
attr_accessible :firstname,:lastname,:account,:address, :city, :state, :postcode, :homephone
end
However, your model still has those attributes (or columns as you call them). You just can't do a mass assignment (like create or update_attributes) without making them attr_accessible first.
It looks like maybe you did rails generate migration which isn't meant to affect your model. I believe after you create your model everything afterward has to be done manually.
If you really want to effect changes to your database and model at the same time, your best bet might be to delete your migrations and model and do a rails generate scaffold (documentation) to create your entire scaffolding from scratch.
There are no problem to add the new columns manually in the model.

Resources