I'm looking a way to implement a multiple role for a class Address (BillingAddress, ShippingAddress e.t.c) by avoiding using a second table address_roles to my project. Is there any possible way?
My Address model below :
class Address < ActiveRecord::Base
self.inheritance_column = nil
serialize :roles
attr_accessible :street, :number, :postal, :city, :country
end
class InstallationAddress < Address
end
class BillingAddress < Address
end
class ShippingAddress < Address
end
I would like to be able to save roles as an Array such as ["BillingAddress", "InstallationAddress"]
Edit 1: How should I describe it in my model in order to work? For example how InstallationAddress.all is going to return me only the addresses that have role InstallationAddress or if I have a belong_to :user , how user.installation_address will be retrieved.
What you have tried is almost correct. is'nt it..?
1) Add a new column "roles" in the Address model.
2) Make roles as serializable in address model (what you have already written).
3) Include a multiple select dropdown in your view page, where you want to place a dropdown.
<%= form.select :roles,
[["BillingAddress","BillingAddress"], ["InstallationAddress","InstallationAddress"]],
:prompt => "Select Roles",
:multiple => true
%>
You need not to have any new model for address_roles. And, I am sorry if you are not expecting the way like this.
Thanks!!
Related
Here is the question, I have a customer and address model as follows:
class Customer < ActiveRecord::Base
has_one :address, as: :addressable
end
class Address < ActiveRecord::Base
belongs_to :addressable, polymorphic: true
end
I have a customer form with the render address information, for example:
# customers/form
= f.input :name
...
# render form/address
= f.input :apto
= f.input :city
= f.input :references
What I am looking for is to validate the address fields in the customer form, in such a way that if the user does not enter any value then it prevents its creation or update
pdd: The address entity is polymorphic and I can use it in any relationship. But I don't know how to validate its fields when I use it in the form of other relations
If you could help me I would be grateful and thank you very much for taking the time to read me.
UPDATE 22/12/2022
I would like to specifically validate the address fields (apto, city, reference) that are in customers only and not in others entities
Since any other entity can use address and in those entities the fields must be without validation
many thanks to #max who recommended validates_associates, however it validates all addresses
Maybe you are looking for:
validate :validate_fields, if: -> { addressable_type == 'Customer' }
Quick question about a simple problem I am facing (and I want to use as a way to understand a few things about associations and rails in a deeper level). Here goes:
The two associated models are
class Employee < ActiveRecord::Base
attr_accessible :name
attr_accessible :age
belongs_to :role
attr_accessible :role_id
end
class Role < ActiveRecord::Base
attr_accessible :title
attr_accessible :salary
has_many :employees
end
so that every new employee has a fixed salary, according to his role (which is the case most of the times). However, what if I want to set a different salary for a specific employee?
Using simple_form I have so far written the following:
<%= f.input :name, label: 'Employee Name', :required => true %>
<%= f.association :role, as: :radio_buttons, :required => true %>
<%= f.input :salary, label: 'Employee Salary', :input_html => { :value => 0 }, :required => true %>
Which of course gives me a can't mass assign protected attributes: salary error.
To fix that, I added attr_accessible :salary to the Employee model but that just changed the error to unknown attribute: salary.
From what I understand I have to first change something in the new employee and then also in the employee model and controller so it accepts a value for the salary and knows how to handle it, right?
I 've also seen accepts_nested_attributes_for used but I am not entirely sure in which side of the association it should go - as I am not entirely sure the association is architectured in the best way either.
You need to add a salary column to your employees table if you are in fact wanting to allow a custom salary to be specified on the Employee. In your terminal, create a new migration and apply it
rails generate migration AddSalaryToEmployees salary:integer
RAILS_ENV=development rake db:migrate
By the way, you don't need to call attr_accessible multiple times; it accepts an arbitrary # of symbols
attr_accessible :name, :age, :role_id, :salary
Also, since you mentioned it, I'll comment on it: accepts_nested_attributes_for currently has no place in your models (given the code you've shown so far).
To answer the questions raised in your comment:
Isn't that duplication of code (having salary in both models I mean)?
No, they serve two different purposes. :salary in Role is the default salary applied to all Employees associated with that Role. :salary on Employee is an 'override' for special circumstances where an Employee's salary doesn't fit the mold of the Role they're associated with.
It wouldn't make sense to create a custom Role just for this purpose (assuming the custom salary is the only difference for the Employee)
You can't change the salary on the Role itself, because that would affect the salary of the other Employees associated with that Role
And doesn't that need another method (to make sure that the role salary is set as the employee's salary if none is specifically set)?
Another method? No. Customizing the existing attr_reader for salary on Employee to return the default from the Role if an 'override' hasn't been set? If you want
def salary
return role.salary if read_attribute(:salary).blank?
read_attribute(:salary)
end
I'm trying to figure out how to construct a collection_select to include two relationships. Here are my models:
class Country < ActiveRecord::Base
has_many :companies, :dependent => :destroy
end
class Company < ActiveRecord::Base
belongs_to :country
has_many :departments, :dependent => :destroy
end
class Department < ActiveRecord::Base
belongs_to :company
end
When I create a new company I use the following to show a select box based on the relationship.
<%= collection_select(:company, :country_id, Countries.all, :id, :name, :prompt => 'Please select country') %>
But for the departments I'd like to have a select which let's the user select it's company from a select which also includes the companies country, formatted in the following way:
Company 1 - Country 1
Company 2 - Country 1
If i use the following I will only get a list of all the companies which I'd like to be able to see from the list which country they are from.
<%= collection_select(:device, :cabinet_id, Cabinet.all, :id, :name, :prompt => 'Please select cabinet') %>
Is there a way for rails to pull the information for the country into a select and append the entry with it's parent country?
I hope I've worded this question correctly! Sorry if it isn't clear.
Even if #jvnil solution works, I think you should avoid putting this logic in your view.
Instead, you could create an instance method in your Company model and use it in your select.
In your model :
class Company< ActiveRecord::Base
def name_for_select
name + " - " + country.name
end
end
And in your view :
<%= collection_select(:department, :company_id, Company.all, :id, :name_for_select %>
Use
UPDATE: move logic code to model
# company.rb
def company_with_country
"#{name} - #{country.name}" # this is better than using `string + string` since it creates only 1 string
end
# view
collection_select :department, :company_id, Company.includes(:country).all, :id, :company_with_country
UPDATE: faster version because it only uses needed columns
# controller
#companies = Company.joins(:country)
.select('companies.id, companies.name, countries.name AS country_name')
.map { |c| ["#{c.name} - #{c.country_name}", c.id] }`
# view
select :department, :company_id, #companies
In my models, BookHeader has many Category
So, when edit or create new BookHeader, the form show like this
Enum fix?
I wanna change the "category #{id}" to category name by define a category_enum method but it still don't work. Please help!
Code for BookHeader model
class BookHeader < ActiveRecord::Base
attr_accessible :autho, :category_id, :description, :title, :book_type, :year,:publisher_id,:detail
has_many :books
belongs_to :category
belongs_to :publisher
TYPE = {:ebook=>"Ebook",:paper_book=> "PaperBook",:magazine=> "Magazine",:media=> "Media"}
DEFAULT_TAB = :paper_book
BOOKS_PER_PAGE = 1 # books to show in a pages (pagination)
extend FriendlyId
def book_type_enum #it worked here
TYPE.map{|key, val| [val]}
end
def category_enum #but dont' work here
["a","b"]
end
Code for edit form
edit do
field :title
field :description, :text do
ckeditor do true end
end
field :autho
field :book_type
field :category
end
See the Division attribute in this link
alias_attribute :name, :you_field_you_want_to_display
I think it's more flexible way, there is no need to rename something and everything will work properly
Yeah, I just found the answer, rename a column in your model to "name", it seem to be very magical, but it worked!
A Contact has a User assigned to them:
class Contact < ActiveRecord::Base
...
belongs_to :user
...
end
The user model has a field I want to exclude any time a user object or objects are returned from db. One of the ways to make it work is to add a default scope:
class User < ActiveRecord::Base
...
has_many :contacts
...
default_scope select((column_names - ['encrypted_password']).map { |column_name| "`#{table_name}`.`#{column_name}`"})
end
So in console if I do:
User.first
The select statement and result set do not include 'encrypted_password'.
However, if I do:
c = Contact.includes(:user).first
c.user
they do. The default scope on the User model does not get applied in this case and the 'encrypted_password' field is shown.
So my question is why? And also, is there a clean way to specify what fields should be returned on related object(s)?
You should just be able to use the :select option on the belongs_to relationship. Something like this:
class Contact < ActiveRecord::Base
...
belongs_to :user, :select => [:id, :first_name, :last_name, :email]
...
end