Attr_accessor use table name - ruby-on-rails

Hi i have a problem with "attr_accessor" in rails 4
I have a model with many associations and when I use attr_accessor I put the field_name but with my association i have many table with the same field name.
For exemple
class User < ActiveRecord::Base
has_one :agent
has_one :language
attr_accessor :code
end
But i have a field :code in agent table and in language table.
I'm trying to find a solution on internet but without success
Is there a way to specify the table name ?

You can use these way to get model speicific code from user model
class User < ActiveRecord::Base
has_one :agent
has_one :language
delegate :code, to: :agent, prefix: true, allow_nil: true
delegate :code, to: :language, prefix: true, allow_nil: true
end
As an example:
Now you can access it User.first.agent_code for agent model Also you can access it User.first.language_code for language model
You can access the specific code by specific model wise

To specify table name expicitly use
class User < ActiveRecord::Base
self.table_name = "table_name"
end

Related

Validation for dependent create in rails

Here are two models
Product and Variant
class Product.rb
has_many :variants, dependent: :destroy
end
class Variant.rb
belongs_to :product
end
Variant.create(product_id:rand(500..3000))
The above line creates a variant in the db even if product is not present with that particular id.
To handle this,
in before_create I could query and check if product is present.
Other than this is there any in-built method or function that rails provides to handle such cases.
It should be like below in variant.rb
class Variant < ApplicationRecord
belongs_to :product
end
In Rails 5, whenever we define a belongs_to association, it is required to have the associated record present by default after this change.
In Rails 4.x world To add validation on belongs_to association, we need to add option required: true .
class Variant < ApplicationRecord
belongs_to :product, required: true
end
Try:
class Variant.rb
belongs_to :product
validates :product, presence: true
end
According to the docs, this will ensure the product record actually exists.
BTW, it should be belongs_to :product, not belongs_to :products.
In Rails 5 by default the reference is required when you specify a belongs_to relation. You need to specify optional: true in case you do not want any compulsion on reference presence.
In Rails 4, you need to specify required: true to ensure the reference object is present and valid.
belongs_to :product, required: true
You can checkout the blogpost below:
https://blog.bigbinary.com/2016/02/15/rails-5-makes-belong-to-association-required-by-default.html
Hope this helped.

Associated Model Attribute Inheritance

Rails novice here. I have associated models Team and Venue defined as follows:
class Team < ApplicationRecord
has_many :home_venues, class_name: "Venue"
end
and
class Venue < ApplicationRecord
belongs_to :team, optional: true, foreign_key: :team_id
end
Both models have attributes :city and :region. When I call team.home_venues.create, I would like for the :city and :region values of newly-created venue to default to the :city and :region values of the creating team unless otherwise specified.
What's the best way to achieve this functionality?
I would use before_validation hook - this way you will make sure you will have all validations run at correct time. In your Venue model:
before_validation :set_default_values
def set_default_values
self.city ||= self.team.try(:city)
self.region ||= self.team.try(:region)
end

How can I validate an associated model?

Is my first time building a custom validation , since trying to the regular ORM validations did not work. I have a model called AdGroup which belongs to another model called Car. I want to send prevent that a user creates a new Ad Group if they have not selected a car. Also the Car is a file.
class AdGroup < ActiveRecord::Base
belongs_to :car
validate :validate_car_id
def validate_car_id
car = Car.find_by(id: params[:id])
if car.nil?
errors.add(:car, "Select a car image")
end
end
end
class Car < ActiveRecord::Base
validates :make, :model, :year, presence: true
validates :file, presence: true
belongs_to :make
has_many :ad_groups
...
end
Is an image that I am trying to select .
Your Ad Group model needs to be associated with the Car model. AdGroup models should have belongs_to :car line and the Car model needs has_many :ad_groups.
To validate associated models you could use ActiveRecord's validates_associated. Be sure to read the docs by the link for gotchas.
class AdGroup < ActiveRecord::Base
belongs_to :car
validates :car, presence: true
validates_associated :car
end
When using validates_associated you don't have to do custom validation.

more than one entry saved on has_one association rails

I am trying to create a has_one association among two model.
class User < ActiveRecord::Base
has_one :emergency_contact
end
class EmergencyContact < ActiveRecord::Base
belongs_to :user
end
when i try to test it through rails console more than one entries are saved for the emergency contact model for a single user. Although when i retrieve it using User.emergency_contact only the first entry is returned. When saving how can i make it to rollback for more than one entry
You can simply validate uniqueness of user_id column in EmergencyContact:
class EmergencyContact < ActiveRecord::Base
belongs_to :user
validates_uniqueness_of :user_id, allow_nil: true
end

How to use foreign key in model and form builder?

I have two models: User and Location as below:
class User < ActiveRecord::Base
attr_accessible :location, :password, :user_name, :password_confirmation
validates :location, :user_name, :presence => true
validates :password, :presence => true, :confirmation => true
has_one :location, :foreign_key => 'location'
end
class Location < ActiveRecord::Base
attr_accessible :loc_id, :loc_name
belongs_to :user, :foreign_key => 'loc_id'
end
You can see that I use the custom foreign_key for the models. I use form builder to build a user sign up form, but when I submit data the error occurs:
Location(#2170327880) expected, got String
I use simple_form to build the form, related code is:
= f.input :location, :collection => Location.all.collect {|c| [c.loc_name, c.loc_id]}
How can I resolve this problem? Or must I use the default foreign_key like location_id for the association?
Thanks.
Update:
When I rename the location field in User model to loc_id and remove the :foreign_key like this:
class User < ActiveRecord::Base
attr_accessible :loc_id, :password, :user_name, :password_confirmation
validates :loc_id, :user_name, :presence => true
validates :password, :presence => true, :confirmation => true
has_one :location, :foreign_key => 'location'
end
class Location < ActiveRecord::Base
attr_accessible :loc_id, :loc_name
belongs_to :user
end
It works fine. But I still want to know how to associate the User and Location model.
P.S. I use Location model to store the country code and country name, which will never update by User.
It sounds like you actually want to have
class User < ActiveRecord::Base
belongs_to :location
end
class Location < ActiveRecord::Base
has_many :users
end
This means that a user has a location_id column. If you do things the other way around (user_id column on location) then a given location can only be associated to one user. The rails way is that location_id on users 'points' at the id column in the locations table. If you want it to point at a different column, use the :primary_key option (The :foreign_key option would be if you wanted the column on users to be called something other than location_id)
In terms of the form, you can't do f.select :location - forms don't know how to transfer a complicated object like that. In these cases you want to set the form to control the location_id attribute, i.e.
= f.input :location_id, :collection => Location.all.collect {|c| [c.loc_name, c.id]}
If you go down the route of having the location id column refer to the loc_id column on location, then you'd need to change that to be
= f.input :location_id, :collection => Location.all.collect {|c| [c.loc_name, c.loc_id]}
Personally if you're only just starting out with rails I'd stick to the defaults
It looks like you're misusing foreign key. In the User model, you should have just has_one :location and the location model should have a user_id attribute. In the location model, you only need to write belongs_to :user. A foreign key is always an index into another (foreign) table.
class User < ActiveRecord::Base
# stuff
has_one :location
end
class Location < ActiveRecord::Base
# more stuff
belongs_to :user
end
If what you ultimately want to do is select all users with the same location, you might want to set the models up a little differently. Right now, because each user has its own location record in the location table, you would end up with duplicate locations, and you'd have to find all of these for a unique location and extract the user_ids from them.
Instead do this
class User < ActiveRecord::Base
has_one :placement
has_one :location, through: :placement
end
class Placement < ActiveRecord::Base
belongs_to :user
belongs_to :location
end
class Location < ActiveRecord::Base
has_many :placements
has_many :users, through: :placements
end
. As for the migrations, Placement should have a :user_id and :location_id. You can drop the :user_id that you currently have in Location. What this code says is that we have many users and we have many unique locations, and we place users in unique locations by creating placements, which indicate that a user with :user_id is located in location with :location_id. Also, don't forget to add a the line
add_index :placements, [:user_id, :location_id], unique: true
so that you can't place a user in a location more than once.
EDIT: Forgot to add: you can get all users in a location by simply getting the location record and calling location.users

Resources