Accepts nested attributes for multiple records - ruby-on-rails

I have two resources: Recommendations and Ratings.
Recommendations Model:
class Recommendation < ActiveRecord::Base
has_many :ratings
accepts_nested_attributes_for :ratings
end
Ratings Model:
class Rating < ActiveRecord::Base
belongs_to :recommendation
end
Recommendations Controller:
class RecommendationsController < ApplicationController
def index
#product = Product.find(params["product_id"])
#recommendations = Recommendation.find(:all, :joins => :products, :conditions => ["product_id = ?", (params["product_id"])])
#recommendation = Recommendation.new
#rating = Rating.new
end
def create
#need to find_or_create new rating based on recommendation_id
end
end
Recommendations Index:
<div id ="prods_container">
<%= form_for #recommendation do |f| %>
<%= f.fields_for #rating do |r| %>
<% #recommendations.each do |rec| %>
<%= rec.title %>
<div id="rec_note_text"><%= r.text_field :notes %></div>
<% end %>
<%= f.submit %>
<% end %>
<% end %>
</div>
I am trying to add a notes field for each of the "recommendation" objects which I need to update the ratings table in my create action/recommendations controller. How do I pass the correct ID's to my controller to achieve this?

Related

How to make columns from joined tables available in Ransack attribute field?

I want to display belongs_to relationship columns in ransackable attributes list. So that I can display them in the dropdown, and perform an advanced search on the (joined) table.
How can I do that?
Below my model, where each manifest has one consignee. I've adjusted the attribute list, but when I select the consignee name it looks for 'manifest'.'name' and not in 'consignee'.'name' via a JOIN.
When I use the simple search form, it works correctly.
manifest.rb
class Manifest < ApplicationRecord
belongs_to :shipper
belongs_to :consignee
...
def self.ransackable_attributes(auth_object = nil)
super - ['id', 'created_at', 'updated_at', 'consignee_id']
super + ['consignee_name']
end
end
consignee.rb
class Consignee < ApplicationRecord
has_many :manifest, dependent: :destroy
...
end
manifest_controller.rb
...
def index
#search = ransack_params
#search.build_grouping unless #search.groupings.any?
#manifests = #search.result(distinct: true)
#search.build_condition
...
private
def ransack_params
Manifest.includes(:vessel, :pod, :pol, :por, :del, :consignee).ransack(params[:q])
end
end
index.html.erb
<%= search_form_for #search do |f| %>
<%= f.condition_fields do |c| %>
<div class="field">
<%= c.attribute_fields do |a| %>
<%= a.attribute_select %>
<% end %>
<%= c.predicate_select :only => [:cont, :not_cont, :matches]%>
<%= c.value_fields do |v| %>
<%= v.text_field :value %>
<% end %>
</div>
<% end %>
I expect to see Consignee Name in the dropdown list, but only see 'Name' at the bottom. When I select this and press search it returns with an error:
undefined method `type' for nil:NilClass
on line: Manifest.includes(:vessel, :pod, :pol, :por, :del, :consignee).ransack(params[:q])
manifest.rb (define ransackable_attributes only for this model)
class Manifest < ApplicationRecord
belongs_to :shipper
belongs_to :consignee
...
private
def self.ransackable_attributes(auth_object = nil)
super - ['id', 'created_at', 'updated_at', 'consignee_id']
end
end
consignee.rb (define ransackable_attributes for this model)
class Consignee < ApplicationRecord
has_many :manifest, dependent: :destroy
...
private
def self.ransackable_attributes(auth_object = nil)
if auth_object == :manifest_search
['name']
else
super
end
end
end
manifest_controller.rb
...
def index
#search = ransack_params
#search.build_grouping unless #search.groupings.any?
#manifests = #search.result(distinct: true)
#search.build_condition
...
private
def ransack_params
Manifest.ransack(params[:q], auth_object: :manifest_search)
end
index.html.erb (add the associations parameter to attribute_select)
<%= search_form_for #search do |f| %>
<%= f.condition_fields do |c| %>
<div class="field">
<%= c.attribute_fields do |a| %>
<%= a.attribute_select :associations => ["consignee"] %>
<% end %>
<%= c.predicate_select :only => [:cont, :not_cont, :matches]%>
<%= c.value_fields do |v| %>
<%= v.text_field :value %>
<% end %>
</div>
<% end %>
note that the auth_object conditional is optional, but it allows you to have different search pages with different attributes. For example, the consignee page could have its own search form showing all of consignee's attributes, while the manifest search shows only the consignee name as a searchable attribute.
I removed the includes to simplify the code; it's not required to make the search work. If you need those associations pre-loaded, you can put it back in.

save multiple columns in one form

I want a User to be able to answer all questions that are assigned to them, in an Answer model. Now I'm trying to create a form that allows me to loop through the questions a User have assigned to them, and answer them in an Answer model.
In the answer model I save the reply, and the question id. However this requires multiple saves in one form, which I'm unable to do.
Model associations look like this:
User
has_many :answers
has_many :questions, through: :question_participants
Answer
belongs_to :user
belongs_to :question
now I'm trying to create an Answer#new form like this:
<%= form_for #answer do |f| %>
<% #questions.each do |question| %>
<h3><%= question.name %></h3>
<%= f.hidden_field :question_id, value: question.id %>
<%= f.text_field :reply, class: 'form-control' %>
<% end %>
<%= f.submit 'Send inn', class: 'btn btn-success' %>
<% end %>
and thus hoping it will allow me to save multiple columns in one, but that doesn't work. It only saves the last column, no matter what.
My answers controller:
class AnswersController < ApplicationController
def new
#questions = current_user.questions
#answer = current_user.answers.new
end
def create
#questions = current_user.questions
#answer = current_user.answers.new(answer_params)
if #answer.save
redirect_to answers_path
else
render 'new'
end
end
private
def answer_params
params.require(:answer).permit(:reply, :question_id)
end
end
What you're looking for is accepts_nested_attributes_for:
This should work:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :answers
has_many :questions, through: :answers
accepts_nested_attributes_for :answers
#this will have to be populated on user create
before_create :build_answers
private
def build_answers
questions = Question.find [1,3,4,6]
questions.each do |question|
user.build_answer(question: question)
end
end
end
#app/models/answer.rb
class Answer < ActiveRecord::Base
#columns id | user_id | question_id | response | created_at | updated_at
belongs_to :user
belongs_to :question
end
#app/models/question.rb
class Question < ActiveRecord::Base
has_many :answers
has_many :users, through: :answers
end
This will give you the ability to do the following:
#config/routes.rb
resources :answers, only: [:edit, :update]
#app/controllers/answers_controller.rb
class AnswersController < ApplicationController
def edit
#questions = current_user.questions
end
def update
#answers = current_user.answers.update answer_params
end
private
def answer_params
params.require(:answer).permit(:response) #-> question_id and user_id set on create, don't need to be changed
end
end
This will allow you to use the following form:
#app/views/answers/edit.html.erb
<%= form_tag answers_update_path, method: :patch do |f| %>
<% #questions.each do |question| %>
<%= f.fields_for "answers[]", question do |qf| %>
<%= qf.label question.title %>
<%= qf.text_field :response %>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
--
Typically, you'd use the accepts_nested_attributes_for with the nested model. However, since you just want multiple answer responses, you can use the above.
The bugs in this would likely be in the strong params, or in the form declaration (IE current_user.questions). If you reply with information, I'll write some upates
Ref: Multiple objects in a Rails form

Ruby on Rails: Polymorphic Association with Nested Attributes, fields not showing

I have a polymorphic association form and I'd like to build a nested form, but the fields are not showing up:
views/reviews/_form.html.erb:
<%= form_for [#reviewable, #review] do |f| %>
<%= f.fields_for :review_images do |i| %>
<%= i.file_field :image %>
<% end %>
<% end %>
review.rb:
class Review < ActiveRecord::Base
attr_accessible :review_styles_attributes
belongs_to :reviewable, polymorphic: true
has_many :review_styles
accepts_nested_attributes_for :review_images, allow_destroy: true
end
review_image.rb:
class ReviewStyle < ActiveRecord::Base
attr_accessible :review_id, :image
belongs_to :reviewable, polymorphic: true
belongs_to :review
end
reviews_controller.rb:
class ReviewsController < ApplicationController
before_filter :get_reviewable
def new
#review = #reviewable.reviews.new
#review_style = #review.build_review_style
3.times {#review.review_styles.new}
end
def edit
# not sure what goes here if I need to edit as well
end
private
def get_reviewable
#reviewable = params[:reviewable].classify.constantize.find(reviewable_id)
end
def reviewable_id
params[(params[:reviewable].singularize + "_id").to_sym]
end
end
I think your problem is here:
<%= f.fields_for :review_images do |i| %>
<%= i.file_field :image %>
<% end %>
From looking at your code, it should be:
#app/views/reviews/new.html.erb
<%= f.fields_for :review_styles do |i| %>
<%= i.file_field :image %>
<% end %>
#app/controllers/reviews_controller.rb
def new
#review = #reviewable.reviews.new
#review.review_styles.build
end
You should note when you're building associative values, you should use .build for plural / multiple associations, and build_ for singular

Passing Checkbox values to model

I am making a model where users can belong to multiple teams and teams have multiple people.
I have checkboxes but they don't pass the value onto the object.
class User < ActiveRecord::Base
attr_accessible :email, :name
has_many :teams
accepts_nested_attributes_for :teams
end
class Team < ActiveRecord::Base
has_many :users
attr_accessible :name
end
Here is the code in my controller
def create
#users = User.all
#user = User.new
#teams = Team.all
#user.attributes = {:teams => []}.merge(params[:user] || {})
end
Here is the code in my view file
<%= form_for #user, url: {action: "create"} do |f| %>
<%= f.label :teams%>
<% for team in #teams %>
<%= check_box_tag team.name, team.name, false, :teams => team.name%>
<%= team.name -%>
<% end %>
<%= submit_tag "Create User" %>
I am trying to show it into
<%= user.teams.name %>
But the only output is "Team"
Can someone tell me what I am doing wrong?
Actually, you can't do a many-to-many relationship that way... you need to do has_many :through or alternatively has_and_belongs_to_many Nice explanation here...
http://guides.rubyonrails.org/association_basics.html

Rails: Polymorphic Associations: How to list associations

I have a polymorphic assocation:
class User < ActiveRecord::Base
belongs_to :companiable, :polymorphic => true
end
class Agency < ActiveRecord::Base
has_many :users, :as => :companiable
end
class Publisher < ActiveRecord::Base
has_many :users, :as => :companiable
end
and now I want to list all users and show the company they belong to. Is there a more elegant solution than this (strongly hope there is)?
def index
#publishers = Publisher.all
#agencies = Agency.all
#users = User.all
end
...
<td><% unless user.companiable_id.nil? %>
<% if user.companiable_type == "Agency" %>
<%= #agencies[user.companiable_id].name %>
<% elsif user.companiable_type == "Publisher"%>
<%= #publishers[user.companiable_id].name %>
<% end %>
<% end %>
</td>
You can acces the company from user, since the belongs_to adds a method so that you can access the other object directly by doing user.companiable
def index
#users = User.all
end
and in your view
<td><% unless user.companiable.nil? %>
<%= user.companiable.name %>
<% end %></td>

Resources