My problem is that I try to invoke an association to a table. I get the ID number but want to get a different field from it. when will this problem up
Model
class Category < ActiveRecord::Base
has_many :suppliers
end
class Supplier < ActiveRecord::Base
belongs_to :categories
end
class Supplier < ActiveRecord::Base
belongs_to :categories
end
Controller
def index
#suppliers = Supplier.all
end
View :
<% #suppliers.each do |s|%>
<td><%= s.name %></td>
<td><%= s.inspect %></td>
<% s.categories.each do |c|%>
<td><%= c.inspect %></td>
<%end%>
<% end %>
errormesseage : uninitialized constant Supplier::Categories
If you have category_id column in your suppliers table then you should declare the belongs_to association as below.
class Supplier < ActiveRecord::Base
#not
#belongs_to :categories
belongs_to :category
end
Your supplier model should have a category_id field (singular), not a categories_id field (plural).
Once you've done that, change your model to
class Supplier < ActiveRecord::Base
belongs_to :categories
end
and everything will start working.
If English is not your first language it might not be obvious, but Rails tries to stick to English linguistic conventions. So, because a supplier only belongs to a single category, you use the singular form when talking about the relationship.
This is the same logic that means your class is [a single] Supplier but the database table contains suppliers
Related
I have been stuck on this problem for a while.
Need to make a form for competitions category with custom inputs. It should take all values from Information table and build the inputs, but the tricky part is that it should be saved to Category_informations table.
class Competition < ApplicationRecord
has_many :categories
has_many :informations
end
class Category < ApplicationRecord
belongs_to :competetion
has_many :category_informations
has_many :information, through: competition
end
class CategoryInformation
belongs_to :catagory
belongs_to :information
end
class Information < ApplicationRecord
belongs_to :competetion
has_many :category_informations
end
Competition -> name
Category -> name, competition_id
Information -> name, competition_id
Category_informations -> value, category_id, information_id
Take a look at this gem: https://github.com/plataformatec/simple_form
Simple Form aims to be as flexible as possible while helping you with powerful components to create your forms.
Let's take a simple example:
class Machine < ActiveRecord::Base
has_many :parts , inverse_of: :machine
accepts_nested_attributes_for :parts
end
class Part < ActiveRecord::Base
# name:string
belongs_to :machine
end
With these models, we can use simple_form to update the machine and its associated parts in a single form:
<%= simple_form_for #machine do |m| %>
<%= m.simple_fields_for :parts do |p| %>
<%= p.input :name %>
<% end %>
<% end %>
For 'new' action, build the nested model from the controller:
class MachinesController < ApplicationController
def new
#machine = Machine.new
#machine.parts.build
end
end
Source: https://github.com/plataformatec/simple_form/wiki/Nested-Models
Sounds to me like you're looking for accepts_nested_attributes_for
See:
https://apidock.com/rails/v3.2.3/ActiveRecord/NestedAttributes/ClassMethods/accepts_nested_attributes_for
https://rubyplus.com/articles/3681-Complex-Forms-in-Rails-5
Also, check out the cocoon gem.
I am having issue with saving a has_many through relation with nested attributes. Due to complexity and requirment in the application the relation is as follows
Table structure,
agreements:
id
agreement_rooms:
id
agreement_id
room_id
details:
id
agreement_rooms_id
For more clarification, agreement_rooms table is related to many other models which will be having agreement_rooms_id in them.
Rails Associations,
class Agreement < ActiveRecord::Base
has_many :details,:through => :agreement_rooms
accepts_nested_attributes_for :details
end
class AgreementRoom < ActiveRecord::Base
has_many :details
end
class Detail < ActiveRecord::Base
belongs_to :agreement_room
accepts_nested_attributes_for :agreement_room
end
When i try to create a agreements record with details hash in it, i get the following error,
Agreement.last.details.create()
ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection: Cannot modify association 'agreement#details' because the source reflection class 'Detail' is associated to 'agreementRoom' via :has_many.
I am not sure how to get this nested attributed working with has_many through relation for the above example. Please help out to figure the issue.
Thanks in advance.
#app/models/aggreement.rb
class Agreement < ActiveRecord::Base
has_many :agreement_rooms
accepts_nested_attributes_for :agreement_rooms
end
#app/models/agreement_room.rb
class AgreementRoom < ActiveRecord::Base
belongs_to :agreement
belongs_to :room
has_many :details
accepts_nested_attributes_for :details
end
#app/models/room.rb
class Room < ActiveRecord::Base
has_many :agreement_rooms
has_many :agreements, through: :agreement_rooms
end
#app/models/detail.rb
class Detail < ActiveRecord::Base
belongs_to :agreement_room
end
--
#app/controllers/agreements_controller.rb
class AgreementsController < ApplicationController
def new
#agreement = Agreement.new
#agreement.agreement_rooms.build.details.build
end
def create
#agreement = Agreement.new agreement_params
#agreement.save
end
private
def agreement_params
params.require(:agreement).permit(:agreement, :param, agreement_rooms_attributes: [ details_attributes: [:x] ])
end
end
#app/views/agreements/new.html.erb
<%= form_for #agreement do |f| %>
<%= f.fields_for :agreement_rooms do |ar| %>
<%= ar.fields_for :details do |d| %>
<%= d.text_field :x %>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
you need to define both associations:
class Agreement < ActiveRecord::Base
has_and_belongs_to_many :agreement_rooms # or has_many if you prefer
has_many :details,:through => :agreement_rooms
accepts_nested_attributes_for :details
end
check the docs
As i said before the model association design we has was not proper and due to poor maintenance it has to be in the same way, atleast for now. So i had to write a dirty patch to fix it.
Its simply skipping nested attributes for this specific model alone, so it can be saved separately by passing the master record id to this record.
As its a dirty solution i'm not marking it as the answer. Just added it hoping someone can have a solution if needed.
Thanks for the help
I want to create a model similar to reddit where users can upvote or downvote a link or article. I am having trouble wrapping my head around this: how do I made my models so that a user can like vote up or down a link only once and be able to change their mine (switch to a downvote) but never be able to vote multiple times no matter how much time has passed/logging out does not matter
has_many :through
You'd create something like this:
#app/models/post.rb
Class Post < ActiveRecord::Base
has_many :votes do
def user(user)
find_by user_id: user.id
end
end
has_many :voters, through: votes, class_name: "User", foreign_key: "user_id"
end
#app/models/vote.rb
Class Vote < ActiveRecord::Base
belongs_to :post
belongs_to :user
end
#app/models/user.rb
Class User < ActiveRecord::Base
has_many :votes
has_many :posts, through: :votes
end
Standard has_many :through relationship - giving you the ability to use a join model to associate two or more other models together:
--
User
This would allow you to call the following:
#app/views/posts/show.html.erb
<% if #post.votes.user(current_user).present? %>
<% link_path = #votes.votes.user(current_user).value == "up" ? vote_down_path : vote_up_path %>
<%= link_to "Vote", link_path %>
<% else %>
# empty vote link
<% end %>
The tricky bit is to associate a single vote with a single user - hence why I included an ActiveRecord Association Extension for your votes association
You can use relationships to capture this...
An Article has many votes
A Vote belongs to a User
A Vote has one article
An article has many voters (users) through Votes but they must be unique. (validation rule)
What is the most efficient way for retrieving all unique venues with a specified set of features?
In the controller, I have:
#venues = Venue.all
#venues = #venues.features.where('feature.id == ' 1).distinct
Here's how my models are defined:
class Neighborhood < ActiveRecord::Base
has_many :venues
end
class Venue < ActiveRecord::Base
belongs_to :neighborhood
has_many :features
end
class FeatureType < ActiveRecord::Base
has_many :features
end
class Feature < ActiveRecord::Base
belongs_to :venue
belongs_to :feature_type
end
Just think about this using English. If a Venue has many Features and you ask "What is the Id of the Feature?" the response is going to be: "There are many Features, which one?"
The :has_many association gives you the following method: venure.features. That gives you all the of the "many" associated features. To get the Id of just one, you could do something like: venue.features.first.id.
Venue has_many features, so you must loop over the collection, vs a belongs_to where there is a single relationship between the models
<% venue.features.each do |feature| %>
<%= debug feature %>
<% end %>
I created a joined table for the models category and products (both created with scaffold). The Product model is this:
class Product < ActiveRecord::Base
belongs_to :category
def category_id
category.id if category
end
def category_id=(id)
self.category = Category.find_by_id(id) unless id.blank?
end
end
and the category model is this:
class Category < ActiveRecord::Base
has_and_belongs_to_many :products
end
In the form.html.erb I create a dropbox with all the classes for the user to choose from:
<p>
<label for="product_category_id">Category:</label><br />
<%= f.collection_select :category_id, Category.find(:all), :id, :name, :prompt => "Select a Category" %>
</p>
Yet when I take a look at the show of the product:
<p>
<b>Category:</b>
<%= #product.category_id %>
</p>
or the list of the products (index.html.erb):
<td><%= product.category_id %></td>
There's no category. Just blank. I don't get it. Is something wrong with the category_id method or the association?
Firstly, you don't need the explicit category_id and category_id= methods. ActiveRecord will handle those for you for a belongs_to association.
Secondly, there seems to be a mismatch between whether you want a has_and_belongs_to_many or a has_many/belongs_to association. If you have a join table then you have the former, in which case both sides of the association should be declared with has_and_belongs_to_many. If you are just using a category_id on the products table then the other end of your association on Category should be has_many :products.
With a join model:
class Categorization < ActiveRecord::Base
belongs_to :category
belongs_to :product
end
you would define in your Product class:
has_many :categorizations
has_many :categories, :through => :categorizations
Then, because your association is a 'many' association, you do not get a .category method on a product. You do however get a categories method (plus several more methods - look at the has_many documentation). If you name your collection_select category_ids then it should work as expected. You may also want to add the 'multiple' option to the select in order to choose more than one category.
Your association is obviously incorrect. As pointed out, the category has_many products. And in case you want to use a many-to-many relationship you're strongly advised to use the has_many :through relationship.