rails joins with module name - ruby

Here is how to join two models
User.where(:id => 1).joins(:posts)
but how to join two models with module/namspace
#schedules= Swimming::Classschedule.joins(:Swimming::Slot).where(:date => #date)
seems not working properly (with error message)
:Swimming is not a class/module
UPDATE
I have updated to
#schedules= Swimming::Classschedule.joins(:swimming_slots).where(:date => #date)
and I do have this table
create_table :swimming_classschedules do |t|
t.integer :slot_id
t.integer :coach_id
t.integer :level_id
t.string :note
t.timestamps
end
create_table :swimming_slots do |t|
t.string :date
t.string :start
t.string :end
t.timestamps
end
Howcome I got this error
Association named 'swimming_slots' was not found; perhaps you misspelled it?
update 2
add this line to Swimming::Classschedule module
belongs_to :swimming_slots ,:class_name=>'Swimming::Slot',:foreign_key => "slot_id"
and
change joins to
#schedules= Swimming::Classschedule.joins(:swimming_slots).where(:swimming_slots =>{:date => #date})
Now it works

you pass the association name to joins. for example, if you have an association like
has_many :swimming_slots, class_name: 'Swimming::Classschedule'
then you pass swimming_slots and rails will do the joins for you.
User.joins(:swimming_slots)
UPDATE:
if slot_id refers to a record in the swimming_slots table, you should have something like
belongs_to :slot, class_name: 'Swimming::Slot'
in your class schedule model. If you have that, you should be able to do
Swimming::Classschedule.joins(:slot)

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

Mysql2::Error: after updating to Rails 4.1

I recently updated my Rails app from 4.0 to 4.1. Everything seems to work fine, except this one line in my Search Model that was working before.
Essentially, I want to search/find District_Resources by Tag Name and by the District_Resource Name.
**ex.**
If I search the word "Tutoring"
*I should get all District_Resources with the Resource_Tag "Tutoring"
*And all District Resources that include the word Tutoring in it's Name.
(i.e Tutoring Services)
For some reason, I keep getting this error:
(Mysql2::Error: Unknown column 'resource_tags.name' in 'where
clause': SELECT `district_resources`.* FROM `district_resources`
WHERE (resource_tags.name like '%Tutoring%' OR district_resources.name like '%Tutoring%')
ORDER BY `district_resources`.`name` ASC):
But that column does exist in the Resource_Tags table.
MODELS
class DistrictResource < ActiveRecord::Base
has_many :district_mappings, dependent: :destroy
has_many :resource_tags, through: :district_mappings
accepts_nested_attributes_for :resource_tags
end
class ResourceTag < ActiveRecord::Base
has_many :district_mappings, dependent: :destroy
has_many :district_resources, through: :district_mappings
end
class Search < ActiveRecord::Base
def district_resources
#district_resources ||= find_district_resources
end
def find_district_resources
district_resources = DistrictResource.order(:name)
district_resources = district_resources.includes(:resource_tags).where("resource_tags.name like :name OR district_resources.name like :name", {:name => "%#{name}%" })
district_resources
end
end
SCHEMA
create_table "district_resources", force: true do |t|
t.string "name"
t.string "description"
t.string "website"
t.string "phone"
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "district_mappings", force: true do |t|
t.integer "district_resource_id"
t.integer "resource_tag_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "resource_tags", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
You are referencing district_resources in where clause but this is not joined in query as you are eager loading resource_tags so here are two solutions for this
1.
district_resources = district_resources.joins(:resource_tags).where("resource_tags.name like :name OR district_resources.name like :name", {:name => "%#{name}%" })
2.
district_resources = district_resources.includes(:resource_tags).refereces(resource_tags).where("resource_tags.name like :name OR district_resources.name like :name", {:name => "%#{name}%" })
In both of these cases we are telling rails that we are using resource_tags table in where clause so join district_resources with it
Fixed it!!
district_resources = district_resources.includes(:resource_tags).where("resource_tags.name like :name OR district_resources.name like :name", {:name => "%#{name}%" }).references(:resource_tags)
I had to reference the Resource_Tags Model

has_many or join - what's the 'rails way' to use my table?

I have a database that keeps track of accidents. Each accident can have multiple causes. Each cause has a friendly name in a 3rd table. What's the 'rails way' to create this association?
Here's what I have:
create_table "accidents", force: true do |t|
t.text "notes"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "causes", force: true do |t|
t.integer "accident_id"
t.integer "cause_name_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "cause_names", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
CauseName.create :name => "DUI"
CauseName.create :name => "Speeding"
Accident:
class Accident ActiveRecord::Base
has_many :causes
end
Causes:
class Cause < ActiveRecord::Base
belongs_to :accidents
has_one :cause_name
end
cause names:
class CauseName < ActiveRecord::Base
belongs_to :causes
end
It seems like to be properly "ORM"'d, I'd use it like this:
Accident.causes.first.cause_name.name #speeding
a = CauseName.find(1)
Accident.causes.first.cause_name = a #set and saved successfully
I've been trying a variety of things, but I can't seem to get my associations to work the way I'd expect. I know I'm not using it right.
I'm very new to rails and activerecord, and horrible with databases... the schema I'm working with was designed by our dba who will be doing reporting on the table, but knows nothing about Ruby or ActiveRecord.
What's the best approach in my situation? Am I even using this thing right?
I think you have your belongs_to and has_one methods placed incorrectly in your Cause - CauseName association.
Quoting the official guide:
If you want to set up a one-to-one relationship between two models,
you'll need to add belongs_to to one, and has_one to the other. How do
you know which is which?
The distinction is in where you place the foreign key (it goes on the
table for the class declaring the belongs_to association), but you
should give some thought to the actual meaning of the data as well.
The has_one relationship says that one of something is yours - that
is, that something points back to you.
So, in your case, it should be like this:
class CauseName < ActiveRecord::Base
has_one :cause # Note that I have changed :causes to singular too
end
class Cause < ActiveRecord::Base
belongs_to :accident # <- Singularized too
belongs_to :cause_name
end
In your case, I'd suggest not splitting causes into two tables. Just cram name into causes table and call it a day.
Then you can easily query like #accident.causes.first.name

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.

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

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."

Resources