Creating models with two words - ruby-on-rails

I have two models one is named BusinessUser and the other is named BusinessPlace.
The BusinessUser can have many BusinessPlaces
class BusinessUser < ActiveRecord::Base
has_many :BusinessPlaces
end
class BusinessPlace < ActiveRecord::Base
belongs_to :BusinessUser
end
When i'm trying to access #business_user.BusinessPlaces.count the sql that get build and run on DB is
SELECT COUNT(*) FROM "business_places" WHERE "business_places"."business_user_id" = 1
but in the migration and in the database the column for business user id is BusinessUser_id which makes the query to fail. Why the sql gets to be build wrong ? I've used the console to create the models.

You just need to set the foreign_key the association will be using for :business_user:
class BusinessUser < ActiveRecord::Base
has_many :business_places
end
class BusinessPlace < ActiveRecord::Base
belongs_to :business_user, :foreign_key => 'BusinessUser_id'
end

You're using the wrong wording for the keys. Your models should look like so:
class BusinessUser < ActiveRecord::Base
has_many :business_places
end
class BusinessPlace < ActiveRecord::Base
belongs_to :business_user
end
so basically use :business_places instead of :BusinessPlaces
if you use migrations to set up your databases you should not need to modify the foreign keys

Related

Rails inconsistent model associations call

I have a rails model for a user as:
class Player < ActiveRecord::Base
has_and_belongs_to_many :character_factors
has_and_belongs_to_many :stats_factors
end
And my character factors model is as:
class CharacterFactor < ActiveRecord::Base
has_and_belongs_to_many :players
end
And my stats factors model is:
class StatFactor < ActiveRecord::Base
has_and_belongs_to_many :players
end
Within my Player model I have the following methods:
def self.character_factors(id)
#character_factors = CharacterFactor.joins(:players).where('players.id = ?', id)
end
and another method:
def self.stat_factors(id)
#stat_factors = StatFactor.joins(:players).where('players.id = ?', id)
end
The join on character factors and players looks for the correct table:
players_character_factors and performs the query properly
whereas the join on stat_factors looks for the table:
stat_factors_players and thus errors out. I'm not sure why it looks for two differently formatted table names for the exact same association. Is there something I'm not doing correctly over here?
I found the solution for my question.
In Rails for HABTM associations the table names are generated automatically in the lexical order of the model names unless explicitly specified.
In my case since I didn't specify the name of the join table so the tables which rails was trying to look for were wrong. I fixed it by updating my models as such:
class Player < ActiveRecord::Base
has_and_belongs_to_many :character_factors, :join_table => :players_character_factors
has_and_belongs_to_many :stats_factors, :join_table => :players_stats_factors
end
and similarly for character factors:
class CharacterFactor < ActiveRecord::Base
has_and_belongs_to_many :players, :join_table => :players_character_factors
end
and for stat factors:
class StatFactor < ActiveRecord::Base
has_and_belongs_to_many :players, :join_table => :players_stats_factors
end

Multiple associations query - DB Modelling

I am planning a rails apps that allows a User to list one/many Vaults, at either their personal address or any other additional address (location) specified against a vault. Before I go ahead and generate the Models I want to make sure I understand what associations need to be set up between the three Models. Here the code representation that I have typed manually to depict what associations are required.
class User < ActiveRecord::Base
has_many :vaults
end
class Vault < ActiveRecord::Base
belongs_to :user
has_one :address
end
class Address < ActiveRecord::Base
belongs_to :user
end
Your database looks okay, few consideration are below :
class User < ActiveRecord::Base
has_many :vaults
has_many :addresses #(optional)if you want to fetch addresses directly
end
class Vault < ActiveRecord::Base
belongs_to :user
has_one :address
end
class Address < ActiveRecord::Base
belongs_to :user #(optional) if you want to fetch user directly
belongs_to :vault
end
Database requirement:
adresses table must contain user_id(optional) and vault_id.
vaults table must contain user_id.

has_and_belongs_to_many STI, restrict to be unique by types

I'm using STI models with has_and_belongs_to_many relations.
So I have User with many Templates of different types, like MainTemplate < Template; NotSoMainTemplate < Template; etc.
Is there a way to limit each user to have only one MainTemplate and only one NotSoMainTemplate, and so on for all types?
Let me reiterate the problem statement as I have understood it.
You want User to have at most one kind of each template. i.e.
1 MainTemplate, 1 NotSoMainTemplate, etc.
You don't need a direct relation with Template (parent table)
Each template may be used by more than one user
Based on the above assumption, I would suggest you to do the following:
Remove existing habtm association between User and Template
Add migrations to add main_template_id, not_so_main_template_id to User
Add the following associations:
class MainTemplate < Template
has_many :users
end
class NotSoMainTemplate < Templete
has_many :users
end
class class User < ActiveRecord::Base
belongs_to :main_template
belongs_to :not_so_main_template
end
Since you are already using STI, you can try has_one.
class Template < ActiveRecord::Base
has_many :users, through: template_choice
...
end
class MainTemplate < Template
...
end
class TemplateChoice < ActiveRecord::Base
belongs_to :template_choice
belongs_to :user
end
class User < ActiveRecord::Base
has_one :main_template, through: :template_choice
has_one :not_so_main_template, through: :template_choice
...
end

Does Rails have a way to handle has_one join tables?

Consider the following model setup:
Model A
has one B1, type: B
has one B2, type: B
Model B
has many A
I want to be able have this work:
class Motorcycle < ActiveRecord::Base
has_one :front_tire, class_name: "Tire"
has_one :back_tire, class_name: "Tire"
end
class Tire < ActiveRecord::Base
has_many :motorcycles
end
The end result would be me being able to do this:
m = Motorcycle.new
ft = Tire.new
bt = Tire.new
m.front_tire = ft
m.back_tire = bt
m.save
Tire.first.motorcycles #=> [...]
You can't have has_many paired with has_one, has_* needs to be paired with belongs_to (of course with exception of has_many :through).
So, you need to either change to motorcycle belongs_to :front_tire or create a third join model.
I think you're looking for basic Single-table Inheritance, as front tires and back tires really aren't the same thing, but rather specific types of tires. To facilitate this, you would need to add a type string column to your tires table, and declare two sub-classes of the Tire class:
class Motorcycle < ActiveRecord::Base
belongs_to :front_tire
belongs_to :back_tire
end
class Tire < ActiveRecord::Base
end
class FrontTire < Tire
has_many :motorcycles
end
class BackTire < Tire
has_many :motorcycles
end
This would allow you to use Tire.first, which would return either an instance of FrontTire or BackTire, which would have many motorcycles. This fulfills your Tire.first.motorcycles requirement.
m = Motorcycle.new
ft = FrontTire.new # id 1
bt = BackTire.new # id 2
m.front_tire = ft
m.back_tire = bt
m.save
Tire.first.motorcycles # returns FrontTire #1
# Or, find specifically by tire type
FrontTire.first.motorcycles # all motorcycles with this front-tire
BackTire.first.motorcycles # all motorcycles with this back-tire
Alternatively, you could simply use a generic tires relationship, now that front and back tires are different classes:
class Motorcycle
has_many :tires
end
class Tire < ActiveRecord::Base
end
class FrontTire < Tire
has_many :motorcycles, foreign_key: :tire_id
end
class BackTire < Tire
has_many :motorcycles, foreign_key: :tire_id
end
Npw Motorcycle.first.tires would return an array of two objects, one instance of a FrontTire and one instance of a BackTire. You would likely want to add a validator to prevent multiple front/back tires being assigned to the same motorcycle.
This is not tested at all but how about something like this:
has_many :motorcycles,
:class_name => 'Motorcycle',
:finder_sql => proc { "select * from motorcycles
where front_tire_id = #{id} OR
back_tire_id = #{id}" }
I think something like this should work
class Tire < ActiveRecord::Base
belongs_to :motorcycle
end
change the has_many :motercycles to belongs_to :motorcycle
Motorcycle has many tires (through has_one)
Tires belong to motorcycle
or you could have used something like
class Motorcycle < ActiveRecord::Base
has_many :tires
end
class Tire < ActiveRecord::Base
belongs_to :motorcycle
end
with Tire containing a column position wich may hold values for front or back
you could create some constants in model to maintain those like
class Tire < ActiveRecord::Base
FROUT 1
BACK 2
#....
end
This is just an another option :)
I managed to solve it with this set of code:
class Motorcycle < ActiveRecord::Base
has_many :tire_brands
has_one :front_tire, class_name: "Tire"
has_one :back_tire, class_name: "Tire"
end
class Tire < ActiveRecord::Base
belongs_to :motorcycle
belongs_to :tire_brand
end
class TireBrand < ActiveRecord::Base
has_many :tires
has_many :motorcycles, through: :tires
end

Cannot get data from related models in Rails

I have 2 models in different namespace.
class Admin::Membership < ActiveRecord::Base
has_many :authorization_roles
end
class AuthorizationRole < ActiveRecord::Base
belongs_to :membership
end
The Membership model is in different folder with AuthorizationRole model (I don't know what is called)
When run Admin::Membership.find(:all), the data from AuthorizationRole model is not included. I've create membership_id field on authorization_roles table, but I still can't get both models related. Is something wrong in this code? Sorry if I'm missing something basic here.
Try this
class Admin::Membership < ActiveRecord::Base
has_many :authorization_roles, :class_name => '::AuthorizationRole'
end
class AuthorizationRole < ActiveRecord::Base
belongs_to :membership, :class_name => 'Admin::Membership'
end
I've never used namespaced models and I don't think you need to... but maybe you'll have to specify the class name in AuthorizationRole, something like:
belongs_to :membership, :class_name => 'Admin::Membership'
UPDATE:
Assuming you have:
class Membership < ActiveRecord::Base
has_many :authorization_roles
end
class AuthorizationRole < ActiveRecord::Base
belongs_to :membership
end
You have added an integer column called membership_id to authorization_roles and you've run the migrations. Now you should be able to create authorization_roles like this #membership.authorization_roles.create( ... ) and fetch them #membership.authorization_roles
Check to see if you are setting the table name prefix. The Rails model generator adds a file like this for namespaced models:
# /app/models/admin.rb
module Admin
def self.table_name_prefix
'admin_'
end
end
Note: this is Rails version 3.0.1 -- not sure about earlier versions.

Resources