How to construct a Rails view to edit an associated data set - ruby-on-rails

I am developing a Rails app to keep track of product manufacturing runs. Each run has a group of products that are made at varying quantities for each run. I have a model, Run, that has many product_run objects which consist of a parameter 'quantity' and a has_one product. I am having trouble constructing a view to enter all of the quantities for a run. Simply display all products with a box to enter a quantity. Any help on the correct Rails way to do this would be appreciated.

Take a look at NestedAttributes ClassMethods
everything that you need should be there.
Active Record Nested Attributes
Nested attributes allow you to save attributes on associated records through the parent. By default nested attribute updating is turned off and you can enable it using the #accepts_nested_attributes_for class method. When you enable nested attributes an attribute writer is defined on the model.
The attribute writer is named after the association, which means that in the following example, two new methods are added to your model:
author_attributes=(attributes) and pages_attributes=(attributes).
#app/model/book.rb
class Book < ActiveRecord::Base
has_one :author
has_many :pages
accepts_nested_attributes_for :author, :pages
end

Related

Rails 5: Many-to-Many relationships and Controllers

Per a previous post , I understand how to set up my tables/Models so that I can setup a Many-to-Many relationship
However, what I am trying to do is to implement all of this on 1 page with 1 form. (The only other page the user will see is a confirmation page after they have submitted the form, possibly just displaying the details of what they submitted)
The User only needs to be able to update the quantities of any of the available Meals. I will then make a backup of the database on a certain day/time and that will be every User's order for the week. Because of this, I have restructured my tables as follows...
User stores the user's information.
user.rb
class User < ApplicationRecord
has_many :mealselections
has_many :meals, through: :mealselections
accepts_nested_attributes_for :mealselections
end
Meal is used to display the information of the meals to all users. (meal_name, description, img_url)
meal.rb
class Meal < ApplicationRecord
has_many :mealselections
has_many :users, through: :mealselections
end
MealSelection is the joined table that references the Meals the User chose, and then an additional integer column is added to this table that denotes the qty of meals they want for each meal selection
mealselection.rb
class MealSelection < ApplicationRecord
belongs_to :user
belongs_to :meals
end
So where I am lost is how to utilize the controller to be able to perform CRUD functionality from a single form. This made more sense when I had a 1-to-1 relationship as I was just updating the columns (meal1, meal2, meal3) for the related user and each meal# column was created with a default value of 0.
However now because of how Many-to-Many relationships work, I realize that the user at minimum has to create and update columns from the same form.
Since I am showing this on one page (homepage), how do I make this happen in the respective HomeController with one form/request?
Though a little dated, the content in http://railscasts.com/episodes/196-nested-model-form-revised demonstrates a common technique which involves modifying the form as the user is making selections to create, remove, or modify the fields of the nested model(s) using javascript. This basic principle is still commonly used, as it leans on the default nested attribute logic in the controller and model mass-update mechanisms. There are some minor tweaks you may have to make with strong parameters being a factor on more modern apps than was common at the time the content was produced. A look at the code for the form and controller action(s) in question might help with a more specific answer as well.

Get all associated data for all records of a model type in Rails?

How do I meld together getting all of the associated data for all of the records of a given model?
I have the following models:
User --N:1--> Reservation <--1:N-- Concert
So pseudo-code:
Reservation belongs_to User
Reservation belongs_to Concert
User has_many Reservations
User has_many Concerts through Reservations
Concert has_many Reservations
Concert has_many Users through Reservations
How do I make a single big array of everything?
I can get all my Reservations via Reservation.all
I can get the User for a particular Reservation via Reservation.find(25).user
I can get the Concert for a particular Reservation via Reservation.find(25).concert
But how do I get it for all of them? If I do
Reservation.all.each do |res|
res.user.name+","+res.concert.name+","+res.concert.date # etc.
end
Then it will do two new database queries for each reservation as it loops through. For 10 records, it might not matter, but for thousands, it can be very painful. Add to it other associations (e.g. Concert belongs_to venue, User has_one email, etc.)...
Is there any way to say, "Get all of the reservations and the following attached info" so it loads in a single SQL query?
What you're trying to accomplish is called eager loading, and can be done using includes in ActiveRecord. See below:
N + 1 queries problem
Active Record lets you specify in advance all the associations that are going to be loaded. This is possible by specifying the includes method of the Model.find call. With includes, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.
http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations
In your example you could use the following:
Reservation.all.includes(:user, :concert)
It is also a good idea to specify the :inverse_of option for your :belongs_to relations. This optimizes object loading and makes sure that cross-referencing a model will point back to the same object in memory, i.e.:
#user == #user.reservations.first.user # true
More information available here:
If you are using a belongs_to on the join model, it is a good idea to set the :inverse_of option on the belongs_to ...
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
In your example:
# app/models/reservation.rb
belongs_to :user, :inverse_of => :reservations
belongs_to :concert, :inverse_of => :reservations

How to make a form with a subform for many-to-many association in Rails 4?

Basically I'd like to do something like this:
Only in my situation I want a User to be able to sign up for many Disciplines with a single form.
What would be the right way of making the form so that I could let the person click in checkboxes what kind of disciplines he/she wants to take part in?
You could look at using rails nested attributes in combination with ryanb's nested form gem.
From the documentation:
Nested attributes allow you to save attributes on associated records
through the parent. By default nested attribute updating is turned off
and you can enable it using the #accepts_nested_attributes_for class
method. When you enable nested attributes an attribute writer is
defined on the model.
At a high level, you would define your classes like so:
class Employee
has_many :orders
accepts_nested_attributes_for :orders
end
class Order
belongs_to :employee
end

Rails - has_many :through and adding existing records from one model to another

I am building an application for test case management system. I have testcases and testruns. I am joining these 2 tables through assocation model called testresults.
class Testcase < ActiveRecord::Base
has_many :testresults
has_many :testruns, :through => :testresults
class Testrun < ActiveRecord::Base
has_many :testresults
has_many :testcases, :through => :testresults
class Testresult < ActiveRecord::Base
belongs_to :testrun
belongs_to :testcase
There is a fixed set of testcases already existing. Everytime I create a new testrun, I want to select a number of existing testcases and add to the new testrun.
I am not sure about the following things. If you could please give me some pointers about what approach should I take and what methods/functions/helpers should I use, I will be grateful. I have wasted more than a day on it going through different posts but not able to see things clearly.
View - How to populate the existing testcases with checkboxes in front of them. Do I use options_from_collection_for_select? But how do i get checkboxes
Do I use testrun model or the assocation model i.e. testresult. I am confused about where to show the added testcases - on the testrun page or testresult page.
Do we create views, and use controllers for the assocaition model as well?
You can:
1. You can use checkboxes (with check_box_tag) or select with multiple options.
2. You can pass the checkboxes in a different hash in the form
3. Get the data of the checkboxes, loop through the data and create the Testresult
The best way is using a has_and_belongs_to_many association, check this video from RailsCasts http://railscasts.com/episodes/17-habtm-checkboxes it is a little old but it works, and if you want a newer video check this out http://railscasts.com/episodes/17-habtm-checkboxes-revised
You should also check http://guides.rubyonrails.org/association_basics.html#the-has_and_belongs_to_many-association

has_and_belongs_to_many why would I want to have attr_accessible of the other model?

If I have two models: Experience and Category which are a many to many association, that looks like this:
class Experience < ActiveRecord::Base
has_and_belongs_to_many :categories
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :experiences
end
Why sometimes people add a:
attr_accessible :category_ids in the Experience model? I have found myself having to do that so in Rails admin gem I can add categories to a particular experience, but I fail to see why.
If you setup a HABTM relation between Experience and Category, you have, besides other things, available method Experience#category_ids. This method returns individual ids of categories the current experience has.
Experience.first.category_ids
Now this method has also Experience#category_ids= variant, so you can use it to assign ids of categories:
Experience.first.category_ids = [1, 2, 3]
Now when you have a form that let's you select categories for an experience, you have only the ids of the selected categories. When you submit the form, those ids get passed to Experience#category_ids= via mass assigment and if you don't have this category_ids in attr_accessible, you get an error.

Resources