Rails 5 - accepts_nested_attributes_for when building multiple objects - ruby-on-rails-5

EDIT 2:
More progress. I can now save the data properly. Now to see if I can update it.
EDIT 1:
I've made some progress and can render the fields in the view with the following code, though I am having trouble saving the data. It also doesn't feel like "the rails way" as they say. Is there a better approach to doing this?
Original Question:
In my application, I have a Daily model which holds a store ID and
timestamps. Each day, for each Store, a form is to be created to
display a field for each service in the Service model. This data
will be saved to a DailyDatum model. One record for each service
which references the daily_id.
So my question is, in the form for creating a new form for the daily
object, how do I render a field for each service in the Service
model?
The Idea:
The user can create a Service.
Each Store has one Daily record for any given date.
Each Daily has many DailyDatum.
Each DailyDatum holds a record of each Service in the services table for that day along with a value.
Updated code:
Daily Controller:
def new
#daily = Daily.new
#services = []
Service.all.each do |s|
service = #daily.daily_data.build
service.service_id = s.id
#services << service
end
end
def create
#daily = Daily.new(daily_params)
if #daily.save
params["services"].each do |service|
data = DailyDatum.new(service_params(service))
data.daily_id = #daily.id
data.save
end
redirect_to dailies_url
else
render 'new'
end
end
private
def service_params(my_params)
my_params.permit(:daily_id, :service_id, :value)
end
Model - DailyDatum.rb
class DailyDatum < ApplicationRecord
belongs_to :daily
belongs_to :service
end
Model - Daily.rb
class Daily < ApplicationRecord
has_many :daily_data
belongs_to :store
accepts_nested_attributes_for :daily_data
end
Model - Service.rb
class Service < ApplicationRecord
belongs_to :service_group, optional: true
has_many :daily_data
end
Model - Store.rb
class Store < ApplicationRecord
has_many :store_users, inverse_of: :store
has_many :users, through: :store_user
has_many :dailies
accepts_nested_attributes_for :store_users, allow_destroy: true
end
View:
<% #services.each do |service| %>
<tr>
<%= fields_for 'services[]', service do |s| %>
<%= s.hidden_field :service_id, value: service.service_id %>
<td><%= s.label :value, service_name(service.service_id) %></td>
<td><%= s.text_field :value %></td>
<% end %>
</tr>
<% end %>

Related

How to create new records with nested attributes in a ruby on rails "has many through" relationship?

I need some advice on building a has many through relationship between USER, THING and EXTRA models.
My USER model is slightly modified inside Devise gem and is noted as Creator whereas other models belonging to USER receive :created_things form.
In my app, USERS create THINGS can later add EXTRAS to their THINGS.
I chose has many through because I want to have unique data on all three models and be able to call both THINGS and EXTRAS from the USER "CREATOR" model.
I have built this many different ways and after 10 years of solving my problems by reading stackoverflow, I am finally submitting this request for support! Thank you for your help.
I have tried creating user and extra references on the THING model and declaring nested attributes in the USER and THING model. I have tried several examples from stackoverflow inside the create and new methods but nothing seems to work.
class User < ApplicationRecord
has_many :created_things, class_name: Thing, foreign_key:
:creator_id, :dependent => :destroy
has_many :extras, through: :created_things
accepts_nested_attributes_for :extras, :reject_if => :all_blank,
allow_destroy: true
class Thing < ApplicationRecord
belongs_to :creator, class_name: User
has_many :extras
accepts_nested_attributes_for :extras, :reject_if => :all_blank,
allow_destroy: true
class Extra < ApplicationRecord
belongs_to :creator, class_name: User, inverse_of: :thing
belongs_to :created_things
Members Index.html.erb
<% if thing.extras.exists? %>
<% thing.extras.each do |extra| %>
<%= extra.title %> <%= link_to "[+]", edit_extra_path(extra) %>
<% end %>
<% else if thing.extras.empty? %>
<%= link_to "+1 EXTRA", new_extra_path(current_user) %>
<% end %>
<% end %>
class MembersController < ApplicationController
before_action :authenticate_user!
def index
#user = current_user
#created_extras = #user.extras
#created_things = #user.created_things
end
class ExtrasController < ApplicationController
def new
#extra = Extra.new
end
def create
#extra = current_user.extras.build(extra_params)
if #extra.save
I am able to create a new EXTRA but the :thing_id remains nul as it does not display when called on the show extra view. Therefore I am not surprised that when I return to the member index page that my thing.extras.exists? call is returning false and the created extra never displays under the THING view. My attempts to modify the extra controller have failed and I some of my reading sugested the extras controller is not necessary in this relationship so I am really at a loss on how this is built. I'm assuming I am missing something in new and create methods maybe in things or user controller? Perhaps I'm missing something in routes resources? Any advice is greatly appreciated. Thank you.
Ok, I figured it out. I really didn't need has many through for this model and I did a lot of testing of the syntax on each model.rb and in the end was able to figure it out from this stackoverflow . . .
[Passing parent model's id to child's new and create action on rails
Here are my the various parts of setting up a has many and belongs to relationship with nested attributes.
class Thing < ApplicationRecord
belongs_to :creator, class_name: User
has_many :extras, inverse_of: :thing, :dependent => :destroy
accepts_nested_attributes_for :extras, allow_destroy: true
class Extra < ApplicationRecord
belongs_to :thing, inverse_of: :extras
extras_controller.rb
class ExtrasController < ApplicationController
def new
#extra = Extra.new(thing_id: params[:thing_id])
end
def create
#user = current_user
#extra = Extra.new(extra_params)
#extra.user_id = #user.id
if #extra.save
flash[:success] = "You have added a new Extra!"
redirect_to #extra #extras_path later
else
flash[:danger] = "The form contains errors"
render :new
end
end
edit.html.erb things
<% if #thing.extras.exists? %>
<p>current extras associated with <%= #thing.title %>: </p>
<% #thing.extras.each do |extra| %>
<p><%= extra.title %> <%= link_to "[+]", edit_extra_path(extra) %>
/ <%= link_to "[-]", extra_path(extra), method: :delete %> </p>
<% end %>
<% end %>
<%= link_to "+1 EXTRA", new_extra_path(thing_id: #thing.id) %>
<%= render 'things/form' %>

Grouping posts by user in has_many through relation collection with Rails 5

I'm trying to display Users (devise) in a collection (has_many through).
<%= #collection.posts.count %> designs by
<% #collection.posts.each do |post| %>
<%= link_to image_tag(post.designer.avatar.url.to_s, class: "avatar-small"), post.designer %>
<% end %>
but it displaying duplicates as in
I need to group by designer.id. So I added #collection_designers line but I could not manage to group by designer id.🤷‍♂️
class CollectionsController < ApplicationController
def show
#collection = Collection.find(params[:id])
#I need to group for designer.id I guess but I could not manage it
#collection_designers = Collection.find(params[:id]).groups(designers.id)
end
...
Relations:
models/collection.rb
class Collection < ApplicationRecord
belongs_to :designer
has_many :collectivizations
has_many :posts, through: :collectivizations
end
models/collectivization.rb
class Collectivization < ApplicationRecord
belongs_to :post
belongs_to :collection
end
models/post.rb
class Post < ApplicationRecord
belongs_to :category
belongs_to :designer
has_many :collectivizations
has_many :collections, through: :collectivizations
You need to find uniq designers ids at first
designer_ids = #collection.posts.distinct.pluck(:designer_id)
And after it find designers by these ids
#designers = Designer.where(id: designer_ids)

Is there a more efficient way than this to load records associated with records in a list?

I have a model Playlist, and a model User, both of which have_many of each other, through a join model PlaylistUser.
On my playlists#show action, I want to print a list of all of a Playlist's Users, along with the first two Playlists associated with each of those Users.
Right now here's what I have:
playlists/show.html.erb
<% #playlist = Playlist.find(params[:id]) %>
<% #playlist.users.each do |user| %>
<%= user.name %>
<%= user.playlists.first.name %>
<%= user.playlists.second.name %>
<% end %>
models
class User < ActiveRecord::Base
has_many :playlist_users
has_many :playlists, :through => :playlist_users
end
class PlaylistUser < ActiveRecord::Base
belongs_to :playlist
belongs_to :user
end
class Playlist < ActiveRecord::Base
has_many :playlist_users
has_many :users, :through => :playlist_users
end
But there is an enormous change in performance when I delete the user.playlists lines and print out only the user.name, because then the database only has to make one query, as opposed to hundreds.
Does anyone know of a way to make this more efficient? Maybe I could somehow load all the associated Playlists in the original query?
You can use the includes method to tell Rails to preload associated records with just one query upfront.
Loading from the database is a controller responsibility and should not happen in the view. Therefore, add the following to your controller:
playlist = Playlist.find(params[:id])
#users = playlist.users.includes(:playlists)
And change your view to just iterate over the users array:
<% #users.each do |user| %>
<%= user.name %>
<%= user.playlists.first.name %>
<%= user.playlists.second.name %>
<% end %>

Form not displayed correctly

i have a form consists of the following models
Employee.rb
class Employee < ActiveRecord::Base
attr_accessible :employee_number, :joining_date, :first_name, :middle_name, :last_name,
:gender, :job_title, :employee_department_id, :qualification, :experience_detail,
:experience_year, :experience_month, :status_description, :date_of_birth, :marital_status,
:children_count, :father_name, :mother_name, :husband_name, :blood_group, :nationality_id,
:home_address_line1, :home_address_line2, :home_city, :home_state, :home_pin_code,
:office_address_line1, :office_address_line2, :office_city, :office_state, :office_pin_code,
:office_phone1, :office_phone2, :mobile_phone, :home_phone, :email, :fax, :user_id,
:reporting_manager_id, :employee_grade_id, :office_country_id,
:home_country_id, :employee_category, :employee_position_id
belongs_to :employee_department
has_many :counselor_supervisors
belongs_to :employee_position
def to_label
full_name = first_name + " " + last_name
end
end
EmployeeDepartment.rb
class EmployeeDepartment < ActiveRecord::Base
attr_accessible :code, :name
has_many :employees
has_many :employee_positions
has_many :counselor_supervisors
has_many :batch_leadership_supervisors
def to_label
name
end
end
CounselorSupervisor.rb
class CounselorSupervisor < ActiveRecord::Base
attr_accessible :employee_id, :employee_department_id, :employee_position_id
belongs_to :employee
belongs_to :employee_department
has_many :batch_counselor_supervisors
def to_label
employee.to_label
end
end
BatchCounselorSupervisor.rb
class BatchCounselorSupervisor < ActiveRecord::Base
attr_accessible :counselor_supervisor_id , :employee_department_id , :counselor_batch_id,
:batch_counselor_advisors_attributes
has_many :batch_counselor_advisors
belongs_to :counselor_supervisor
belongs_to :employee_department
belongs_to :counselor_batch
accepts_nested_attributes_for :batch_counselor_advisors
end
Employee_position.rb
class EmployeePosition < ActiveRecord::Base
attr_accessible :position_title, :employee_department_id
has_many :employees
belongs_to :employee_department
def to_label
position_title
end
end
batch_counselor_supervisors/new.html.erb (part of the form which related to my question)
<%= simple_form_for(#batch_counselor_supervisor) do |f| %>
<%= f.error_messages %>
<%= f.association :employee_department, as: :select %>
<%= f.input :counselor_supervisor_id , collection: EmployeeDepartment.all, as: :grouped_select, group_method: :counselor_supervisors %>
<% end %>
the dropdown list appears like this:
If I added an employee which belongs to the first department "Business Administration", the form will be displayed correctly like this:
Update: after adding label_method: :to_label, so my form became like this :
<%= simple_form_for(#batch_counselor_supervisor) do |f| %>
<%= f.error_messages %>
<%= f.association :employee_department, as: :select %>
<%= f.input :counselor_supervisor_id ,
collection: EmployeeDepartment.all, as: :grouped_select, group_method: :counselor_supervisors, label_method: :to_label %>
<% end %>
the employee name displayed correctly but still the department name not displayed correctly as the following image:
Is this SQLite3 issue ? and What can I do in order to solve this if it sqlite3 issue or not.
From what I see, you only have an issue with the labels not being displayed correctly. Could you try to explicitly set the method on your input:
label_method: :to_label
For more information have a look at https://github.com/plataformatec/simple_form and search for *label_method*
What are the actual relevant rows in your Employee table and your EmployeePosition table?
In your Employee table you happen to have these 2 columns;
employee_position_id
employee_position.
Since employee_position is also a table name, it's bad/reduntant model structure which might be confusing your include method of the query. It's possible that in your tables, the rows are fully filled out to complete the first query, but not for any of your other queries even though you think it is.

Show Name instead of ID in a HABTM relationship

Excuse me if I'm being too much of a beginner but none of the other related answers worker.
I want to show the category name that the links belong to instead of the id.
Here's the migration.
class CreateCategoriesLinks < ActiveRecord::Migration
def self.up
create_table :categories_links, :id => false do |t|
t.references :category
t.references :link
end
end
def self.down
drop_table :categories_links
end
end
The categories model
class Category < ActiveRecord::Base
has_and_belongs_to_many :links
end
The links model
class Link < ActiveRecord::Base
has_and_belongs_to_many :categories
end
And here's what's in the links controller under index and show
#categories = Category.find(:all, :order => 'name')
and here's what's in the index right now but, I've tried every permutation of this that I could find.
<%= link.category.name %>
If it put <%= link.category_ids %>, it'll show the ids.
Try:
<% link.categories.each do |cat| %>
<%= cat.name %><br>
<% end %>