In my Ruby on Rails project, I have a Country model class and a Proposal model class. A country has many proposals and a proposal belongs to a specific country. Each proposal consists of 30 questions. I want to display each question for every proposal for that specific country.
My initial idea for syntax was:
<% #country.proposal.each do |proposal| %>
<% end %>
However, this resulted in an error message
undefined method `proposal' for #Country:0x007f67b51cf178
Any ideas?
According to yous associations, just replace #country.proposal.each with
#country.proposals.each. has_many association define method with a name in plural form.
Related
Background
My application defines a one-to-many relationship between Employee and Company models. I've assigned the Employee fixture a company using the label of the Company fixture (37_signals). However, I also need to assign the company_uuid, which is generated by SecureRandom.uuid.
Example
app/models/
employee.rb
class Employee
belongs_to :company
end
company.rb
class Company
has_many :employees
end
test/fixtures/
employees.yml
employee:
name: dhh
company: 37_signals
company_uuid: <%= "Access the 37_signals company fixture's uuid here!" %>
companies.yml
37_signals:
name: $LABEL
company_uuid: <%= SecureRandom.uuid %>
Question
How can I access the attribute of a Fixture in another FixtureSet?
Attempted
I've attempted to use the following lines as solutions:
company_uuid: <%= ActiveRecord::FixtureSet.identify(:37_signals).company_uuid %>
The above finds the company's primary key id value, then calls the company_uuid method, which is undefined for the integer. This is invalid.
company_uuid: <%= companies(:37_signals).company_uuid %>
The above finds reports undefined method 'companies' for main:Object
Is there a conventional way to solve this problem?
Hmmm, the first option should be to DRY out the data, so it only exists in one place. You could do this with a delegate so that employee.company_uuid will always be answered by employee.company.company_uuid.
If you really need it in the Employee model, the next best choice would be to use a callback (like before_validate or after_save depending on your use-case), that copies the value from the Company to the Employee object. You want to eliminate chances for the data value to diverge from what it's true source should be.
Finally, you could extract all the UUIDs into a hash accessible to both fixtures at the time of creation, and set both values like:
company_uuid: <%= UUIDs['37_signals'] %>
...or similar
This is the best solution I've been able to devise:
company_uuid: <%= Company.find(ActiveRecord::FixtureSet.identify(:publish_and_export_album)).company_uuid %>
However, this solution does not seem conventional. Also, I believe that this succeeds with some luck since fixtures are loaded alphabetically. If Company was named Organization, loading after Employee, then I think this would not work as intended. Actually, through trial and error I determined that this method works in the opposite direction, so the alpha-order has no detrimental effect.
This isn't an issue if you use the fixture_builder gem. It allows you to build a graph of model objects and give them fixture names, and saves them to .yml fixture files for you.
I have a Review model. My users should be able to write reviews. The view for the Review#New should be a form with textfields that the admin creates beforehand.
In other words, my admin-user should be able to create multiple instances of a Review model that has different fields, perhaps even of different input types (string, integer, etc.). That way, when a regular user logs in, they see the different form fields that were specified for data collection by the admin user.
Naturally all of that should be stored in the DB for retrieval within the context it was stored (aka for that specific model).
What's the best way to approach this in Rails?
Think of it like a survey form, and a survey form builder.
It would be good if I could do this with Simple-Form, but that's not a requirement.
Edit 1
Here is an example of the type of fields that they should be able to add to a review:
In my experience a good portion of database design is helped by simply finding the right name for things. In your case I think you are on the right track with thinking about surveys or quizzes.
Check out the survey gem for ideas. In it the base model is Surveys. Surveys have many Questions. Questions have many Options. Surveys also have many Attempts which are answered surveys. Attempts then have many Answers.
So the corollary for you could be to have Reviews/Evaluations (created by admins) which might have many Criteria/Inquiries (possibly of different types, but we'll get to that in a minute). Then your users would create Responses/Assessments which would belong to a specific Review/Evaluation and have many Answers/Responses.
For different question types (Short Answer, Likert Scale Rating, 1-10, Tag List, etc) you could use polymorphism on the criteria/inquiries.
Hopefully some of these names I've used will help you. Feel free to use a thesaurus for more inspiration.
EDIT Re:Polymorphism
Disclaimer: polymorphism might be overkill depending on your application.
Sure, I'll expand some. Not exactly. Take a look at the rails guide on polymorphism if you haven't already. I think what you would want is
class Criterion < ActiveRecord::Base
belongs_to :askable, polymorphic: true
end
Then then I would make a model for each question/criterion type. For example:
class ShortAnswer < ActiveRecord::Base
has_many :criteria, as: :askable
end
class Likert < ActiveRecord::Base
has_many :criteria, as: :askable
end
Side note: If rails does not properly pluralize criterion to criteria you may need to add the following to your config/initializers/inflections.rb file
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'criterion', 'criteria'
end
Scratch solution.
From my experience the easiest solution is to use hstore, json or jsonb type of fields.
This solution play good with Postgresql database.
To achieve this approach you need to add field to your Review model.
Migrations:
# Reviews
def change
add_column :reviews, :structure, :json
end
# Answers
def change
add_column :answers, :values, :hstore
end
Then you can define model ReviewStructure plain ruby class, here you can use Virtus gem to serialize it easely:
class ReviewStructure
include Virtus.model
attribute :fields, Array[Field]
class Field
include Virtus.model
attribute :name
attribute :type
end
end
Then define in Review the serialization for structure field:
class Review < ActiveRecord::Base
...
serialize :structure, ReviewStructure
end
Then you can access structure fields of review with review.structure.fields.
In view you can use a simple form
<% simple_form_for #answer do |f| %>
<% #review.structure.fields.each do |field| %>
<% f.input "values[#{field.name}]", as: field.type %>
<% end %>
<% end %>
To access answer results just use:
answer.values.each do |field_name, value|
...
end
Note:
As for admin for it's better to handle creation of review structure on client side(using js), and post pure JSON structure via API.
With such approach you will have ability to create quizzes with different types of field.
Note:
Please keep in mind that current implementation connect one review to one answer, assuming that the answer model contains all the values of user response.
I am confused about the some Association concepts in Active Records.
I have three models User, Bank and Bankaccount. Both the User and the Bank models "has_many" Bankaccounts and the Bankaccount model "belongs_to" both the User and the Bank models. I use the following syntax to create a Bankaccount through its association with User
#bankaccount = #user.bankaccounts.create(bankaccount_params)
What is the appropriate syntax if I want to create a bankaccount object through both the association with User and the association with Bank?
My second question is related to this one. Right now, because I am not sure how to create a bankaccount through both associations, I handle the association with the Bank by putting the parameter manually
bank_id = params[:bank_id]
However, this seems to trigger some issues down the road when I want to iterate through all the bankaccounts and retrieve the name of the associated bank.
In my view I have
<% #bankaccounts.each do |bankaccount| %>
<%= bankaccount.bank %>
I obtained a list of these
#<Bank:0x007f7a66618ef0>
#<Bank:0x007f7a664c9ab8>
If I tried to get the name of the bank
<% #bankaccounts.each do |bankaccount| %>
<%= bankaccount.bank.name %>
I get an undefined method name for nil class. I do get the name of the bank in the console with these simple lines
bankaccount = Bankaccount.find(1)
bankaccount.bank.name
Could you anyone give me more background on those concepts and provide me with the appropriate syntax to loop accross my collection #user.bankaccount and for each bankaccount retrieve the name of the associated bank?
Thanks.
You'll have to choose one association to create a bankaccount through, then set the second separately:
#bankaccount = #user.bankaccounts.new(bankaccount_params)
#bankaccount.bank = somebank
#bankaccount.save
Or
#bankaccount = #bank.bankaccounts.new(bankaccount_params)
#bankaccount.user = someuser
#bankaccount.save
In addition, I don't see why setting the second association manually with a param would inherently cause the other problems you are experiencing. This should be fine (assuming a bank with this id actually exists):
#bankaccount.bank_id = params[:bank_id]
If you choose to assign a foreign key as a parameter, you can roll it into strong parameters and pass it into the bankaccount model with everything else. For example:
def bankaccount_params
params.require(:bankaccount).permit(:bank_id, ...)
end
You last issue regarding arrays vs. collections depends on what you are trying to do. First, if you are particularly interested in the bankaccount's bank name, make it easier to get:
class Bankaccount
belongs_to :bank
...
def bank_name
bank.name
end
end
For those who buy into such things, this also prevents a Law of Demeter violation.
If you are simply trying to list the names of banks for #bankaccounts in a view, try leveraging Rails partials with something like this:
app/views/bankaccounts/index.html.erb
<%= render #bankaccounts %>
app/views/bankaccounts/_bankaccount.html.erb
<%= bankaccount.bank_name %>
More on this here: http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials
If you're looping over #bankaccounts for another reason, the code you provided should work, given that #bankaccounts represents ActiveRecord relations and not a simple array:
<% #bankaccounts.each do |bankaccount| %>
<%= bankaccount.bank_name %>
<% end %>
Since you're getting an undefined method error, your problem probably stems from how you are building #bankaccounts. If you are doing exactly this...
#bankaccounts = #user.bankaccounts
...and you've verified that everything is properly associated in the console, then your problem is likely unrelated to arrays or collections.
I've been trying to switch my Orders model to a polymorphic association with my Product and Service models. However, I have a few questions that I haven't been able to find answers to, even after watching the RailsCast and reading the documentation (so, those suggestions are appreciated, but I need a more concrete answer).
Question:
Is a polymorphic association the best thing to use in this case? Prior to this, I was using a Transaction model that had multiple belongs_to associations and used a custom Parent function to determine which one it was. This was working fine, but someone suggested a polymorphic association may clean things up.
I set up the polymorphic association properly and have been unable to have the transactable_id and transactable_type automatically populated. The code is below. I have side-stepped this by manually putting them in inside the form, but if anyone knows the proper way to do it, that would be great!
How can I access elements with polymorphic associations? For example, in my Cart object (which has_many Transactions and which Transactions belongs_to) I can no longer access things using #cart.transactions.each do |t| ... #t.product.name type coding.
My model associations look like this:
class Order < ActiveRecord::Base
belongs_to :orderable, :polymorphic => true
end
class Product < ActiveRecord::Base
has_many :orders, :as => :orderable
end
My forms used to look like this:
<% form_for [#orderable, #order] do |f| %>
...
<% end %>
And were rendered like this in my Product Show view:
<%= render 'orders/form' %>
Now, I pass a variable for the product.id in the render partial and use it to populate the transactable_id field. But, I feel like that is very messy.
Again, I have read the tutorials and API docs and have been unable to solve this, so any help would be greatly appreciated!!
Answers to your questions:
If your business login implies that multiple models will have related model with the same fields so you should use polymorphic association. (In your case you can use it).
If set up polymorphic association Rails will automatically handle setting *_id and *_type fields depending on associated parent model.
Lets say you have Product with many orders in polymorphic association and you want to define which model order belongs to:
order = Order.first
order.orderable
I am trying to finish building a Rails "Home Inventory" app as an example to help me learn rails. Following gives a general overview of what I am trying to achieve:
The main purpose of this application is to show a page with detailed information.
So, http://localhost:3000/living-room-couch would display the information regarding the couch.
Each Item, can belong one( or has one?) of three categories:
Book
Furniture
Electronics.
Book has the following properties:
- isbn,
- pages,
- address,
- category
Furniture has following properties:
- color,
- price,
- address,
- category
Electronics has following properties:
- name,
- voltage,
- address,
- category.
--
Now on my View side, I have made 3 templates in rails, that contain elements suited to display an item belonging to one of the 3 categories. Template for Book shows isbn, and template for Electronics shows the voltage.
How do I model this in ActiveRecord? I will put it in English, maybe someone can help translate into Rails:
An Item, belongs_to or has_one category. Category can be one of the three: Book, Furniture, or Electronic.
I don't know how to do this. I know that each category like Book will be a model of its own, due to having different characteristics.
Do I need to have Category has a model too, because it would only consist of Book, or Furniture or Electronics. If I was to take the route of making Category a model of its own, how would I make it relate to a model such as Book.
--or
Would I just go this route (or join model perhaps):
class BookModel < ActiveRecord::Base
has_many :categories
End
And then, select to which category belongs, based on the Model name.
I hope I put the question right, I am just so confused regarding this.
Thank You for your time.
Why not have an Item have the following relationships:
belongs_to :book
belongs_to :furniture
belongs_to :electronic
You can then only actually set on of these, and can do a test of
if item.book
#do things
end
for each item, if you care about whether it's a book, etc. You can even use validations to make sure it only ever belongs to one thing at a time.
I don't think you need the category model. You can just create the book, furniture and electronic models and one controller for each one.
Edit
No, there's no advantage. I just said to create different models/controllers because what you're modeling, in my opinion, are different things. But if you think they'll have a lot in common, I'd suggest for you to use single table inheritance. This way you'd have a single table for every item and can have only one controller, but each item would have one model.
the Item model could be declared as polymorphic (se here: http://guides.rails.info/association_basics.html#polymorphic-associations)
so you'll declare Item:
class Item < ActiveRecord::Base
belongs_to :category, :polymorphic => true
end
then the 3 models that act as category (I'll show one, the others are same):
class Employee < ActiveRecord::Base
has_one :item, :as => :category
end
# and so on...
this way you can associate an Item to one of the 3 models (Book, Furniture and Electronics).
each instance of these models will have an 'items' atribute, like this:
#book.items # returns all the items associated to a #book object
You can also use has_many association using a polymorphic model.
For the views, you can use Nested Form Objects (see here: http://guides.rails.info/form_helpers.html). basically, in each form, you should nest a form to create an Item object. to follow the Book example, you'll have something like this:
<%= form_for :book, #book do |form| %>
<%= form.text_field :isbn %>
<!-- other fields -->
<%= fields_for #book.item do |item_form| %>
<%= item_form.text_field :name %>
<% end %>
<% end %>
hope this helped you ;)