I have the following model in my project
class Attribute < ApplicationRecord
validates :name, presence: true
validates :name, uniqueness: true
has_many :attribute_vals
end
and I am trying to do the following in my view
<div id="attributes_list">
<%= #attributes.each do |attr| %>
<% attr.attribute_vals.each do |val| %>
- <%= val.name %>
<% end %>
<% end %>
</div>
where #attributes is equals to Attribute.all.
But when I load the page, the following error is thrown
You tried to define an association named attribute on the model AttributeVal, but this will conflict with a method attribute already defined by Active Record. Please choose a different association name.
My models
class Attribute < ApplicationRecord
validates :name, presence: true
validates :name, uniqueness: true
has_many :attribute_vals
end
.
class AttributeVal < ApplicationRecord
validates :name, presence: true
validates :name, uniqueness: { scope: :attribute_id }
belongs_to :attribute
end
Is there any way I can access this sub collection?
Because ApplicationRecord already using a method named "attribute". I think you should change your model name. But if you want to use like this, you can do like the below:
has_one :association_name, :foreign_key: "key_name", class_name: "ModelClass"
Probably for your project:
class AttributeVal < ApplicationRecord
belongs_to :new_association_name, foreign_key: "attribute_val_id", class_name: "Attribute"
end
Source:
http://blog.blakesimpson.co.uk/read/59-fixing-the-you-tried-to-define-an-association-named-transaction-ruby-on-rails-error
Related
My models look like this:
class Project < ApplicationRecord
has_many :comments
has_many :contractor_projects
has_many :contractors, through: :contractor_projects
validates_presence_of :title, :contract_number, :category, :project_start_date, :project_end_date, :substantial_completion_date, :category, :solicitation_number, :project_officer, :location
accepts_nested_attributes_for :contractor_projects
end
class Contractor < ApplicationRecord
has_many :contractor_projects
has_many :projects, through: :contractor_projects
validates :name, presence: true
validates :email, presence: true, uniqueness: true
end
class ContractorProject < ApplicationRecord
belongs_to :contractor
belongs_to :project
end
The ContractorProject model has an extra attribute #bid_status that I want to reflect on project's show page but it does not appear even though it's in the params when i raised it.
below is sample method for your case
def show
#project = Project.find(params[:id]
#contractors = #project.contractors
end
inside show.html.erb, you have to loop it, since it may get more than one records
<% #contractors.each do |contractor| %>
<%= contractor.bid_status %>
<% end %>
====== CODE =====
Model father.rb & son.rb
class Father < ApplicationRecord
has_many :sons
validates :f_name, presence: true
accepts_nested_attributes_for :sons
end
class Son < ApplicationRecord
belongs_to :father
validates :s_name, presence: true
end
_form.html.erb--fathers
<%= form_for #order do |f| %>
<%= f.text_field :f_name %>
<%= f.fieids_for :sons do |ff| %>
<%= ff.s_name %>
<% end %>
<% end %>
fathers_controller.rb
def create
#father = Father.new father_params
if #father.save
do_something
end
end
======= QUESTION ======
If I save father object like below, it will do validations for both father and son.
Instead, if I change it to #father.save(validate: false), I think this will jump both validations.
What I want is only to do validation for father's attribute.
Is there a way to achieve this?
I think you should add the code below to your model father.rb so that basicly you are rejecting son's attribute from validation and only the father's attribute will be validated:
reject_if: proc { |attributes| attributes['s_name'].blank? }
The final model father.rb will be:
class Father < ApplicationRecord
has_many :sons
validates :f_name, presence: true
accepts_nested_attributes_for :sons,
reject_if: proc { |attributes| attributes['s_name'].blank? }
end
UPDATE
( NOTE: The code above won't save :s_name attribute into DB, as #Marco Song didn't mention in his question)
The solution which works for me, is to add allow_blank: true to Son model. allow_nil: true didn't work for me in Rails 5.0.0.1, Ruby 2.3.1
Also I added inverse_of: to both models to avoid SQL queries, not generating them.
Father model:
app/models/father.rb
class Father < ApplicationRecord
has_many :sons, inverse_of: :father
validates :f_name, presence: true
accepts_nested_attributes_for :sons
end
Son model:
app/models/son.rb
class Son < ApplicationRecord
belongs_to :father, inverse_of: :sons
validates :s_name, presence: true, allow_blank: true
end
I whitelisted son's attributes in Father's controller:
def father_params
params.require(:father).permit(:f_name, sons_attributes: [:id, :s_name])
end
At the end after this setup above, I was able to save :s_name attribute in the DB.
I have a collection select in my form:
<div class="field">
<%= f.label :area %>
<%= f.collection_select(:area_id, Area.all, :id, :name, include_blank: "No area.") %>
And my model validation has no requirement for an area.
It was my understanding that by using include_blank would allow me to choose nil. However i get a validation error "Area must exist"
EDIT:
Here is the important code in the model:
has_many :ratings, dependent: :destroy
has_many :noise_ratings, dependent: :destroy
has_many :statuses, dependent: :destroy
has_many :checkins, dependent: :destroy
has_and_belongs_to_many :features
belongs_to :area
belongs_to :campus
validates :name, presence: true, uniqueness: { scope: :campus_id, message: "unique space for each campus." }
validates :description, presence: true
validates :campus_id, presence: true
Rails 5 forces you to set all belongs_to associations unless you specify optional: true. It was added to prevent data inconsistencies, so, in case you want it to behave like previous rails versions, you just have to change your association to this:
belongs_to :area, optional: true
In Rails 5 validate is set to true by default. Please check for :optional and :required options on belongs_to documentation for more details.
I'm trying to understand how to implement one-to-many relationship through reference table. I'm looking on this guide I though just write on one model has_many so it will be one-to-many but I'm not completely sure (I wrote something but it's not working). Anyway I'm doing this to save for me a table, and doing it right and not just working.
The model is as following:
Microposts, :id, :content
Tag, :id, :name
Tag_microposts, :tag_id, :micropost_id
Article, :id, :text
Article_microposts, :article_id, :micropost_id
I can do two microposts tables with the id of the tag/article. But I think doing it like this is better and righter.
In the end what's interesting me is to get microposts through tag model. So in the tag_controller be able to do:
def index
#tag = Tag.find(params[:id])
#microposts = #tag.microposts
end
Some code:
class Tag < ActiveRecord::Base
...
has_many :tag_microposts, foreign_key: :tag_id, dependent: :destroy
has_many :microposts, through: :tag_microposts, source: :micropost
...
end
class TagMicropost < ActiveRecord::Base
validates :tag_id, presence: true
validates :micropost_id, presence: true
end
class Micropost < ActiveRecord::Base
belongs_to :user
belongs_to :tag
validates :content, presence: true, length: {minimum: 10, maximum: 250}
validates :user_id, presence: true
end
May I ask why you are using a reference table for this? You can do a one-to-many association with only the two models you are associating. If you want to associate a tag with many posts you can just do this in your models.
class Tag < ActiveRecord::Base
has_many :microposts
end
class Micropost < ActiveRecord::Base
belongs_to :tag
#added in edit
belongs_to :article
validates :content, presence: true, length: {minimum: 10, maximum: 250}
validates :user_id, presence: true
end
This should let you do:
#tag.microposts
Just fine. The forgien key will be stored in your Micro post model so be sure to add the column. You can use an active migration for that. Call the column tag_id, rails should take care of the rest.
Edit*
A added the article association. The problem you raised is only relevant if you need to get the article/tag given the micropost. The code to do that is still pretty simple with this model.
#tag ||= #micropost.tag
Using the conditional assignment operator like this will only assign #tag if the association is there. If you give me more specifics about how these models will be used I can give you a better answer.
I have troubles creating the records in an association with rails 4. It's basically an association between Entry and Author, with a join table in the middle called AuthorsEntry. The schema is the following:
class Entry < ActiveRecord::Base
validates :name, presence: true
validates :from, presence: true
validates :to, presence: true
belongs_to :event
has_many :authors, through: :authors_entry
has_many :authors_entry
class AuthorsEntry < ActiveRecord::Base
validates :author, presence: true
validates :entry, presence: true
belongs_to :author
belongs_to :entry
end
class Author < ActiveRecord::Base
belongs_to :event
has_many :entries, through: :authors_entry
has_many :authors_entry
validates :name, presence: true
validates :event, presence: true
end
In my program_entries_controller.rb I have the following methods:
def create
#program_entry = Entry.new(program_entry_params)
author_ids_params.each do |id|
#program_entry.authors << AuthorsEntry.build(author_id: id)
end
#program_entry.event = #event
if #program_entry.save
flash[:notice] = t(:program_entry_created_successfully)
redirect_to organizer_event_program_entry_path(#event, #program_entry)
else
render :new
end
end
def program_entry_params
params.require(:program_entry).permit(
:name, :abstract, :'from(1i)', :'from(2i)', :'from(3i)',
:'from(4i)', :'from(5i)', :'to(1i)', :'to(2i)', :'to(3i)', :'to(4i)',
:'to(5i)'
)
end
def author_ids_params
params.require(:program_entry).permit(:author_ids => [])
end
I already have the authors saved in my database, the create action should just add a new record for the Entry model and the association (authors_entry) table. But when I try saving the entry it always returns "is_invalid" over authors_entry.
The join table should be named AuthorEntries to follow rails convention.