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

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

Related

Request parameters not saving on model_params on n:n relationship with check_box_tag

I am using Rails 5.1 and im having some issues saving params on an n:n relationship.
I have three models:
class Course < ApplicationRecord
belongs_to :studio
has_many :reviews, dependent: :destroy
has_many :has_category
has_many :categories, through: :has_category
validates :name, presence: true
end
class Category < ApplicationRecord
has_many :has_category
has_many :courses, through: :has_category
end
class HasCategory < ApplicationRecord
belongs_to :category
belongs_to :course
end
and a simple form to create a new course with different categories using check_box_tag (not sure if using it correctly though)
<%= simple_form_for [#studio, #course] do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<% #categories.each do |category| %>
<%= check_box_tag "course[category_ids][]", category.id, true %>
<%= category.name%>
<% end %>
<%= f.button :submit %>
<% end %>
And all is permitted and created on the courses controller:
def new
#studio = Studio.find(params[:studio_id])
#course = Course.new
#course.studio = #studio
#categories = Category.all
end
def create
#studio = Studio.find(params[:studio_id])
#course = Course.new(course_params)
#course.studio = #studio
#categories = params[:category_ids]
if #course.save
redirect_to course_path(#course)
else
render :new
end
end
def course_params
params.require(:course).permit(:studio_id, :name, :description, :category_ids)
end
With better_errors i know the categories are being requested, here the request info:
"course"=>{"name"=>"Course test", "description"=>"testing", "category_ids"=>["2", "3"]}, "commit"=>"Create Course", "controller"=>"courses", "action"=>"create", "studio_id"=>"16"}
but the categories are not saved on course_params, HasCategory instance or on the Course, i´ve tried with #course.categories = params[:category_ids] and other solutions without success.
How do i save the categories to the courses?
Try the following
Change the strong parameter with category_ids: []
def course_params
params.require(:course).permit(:studio_id, :name, :description, category_ids: [])
end
Comment out this line #categories = params[:category_ids]
Hope it helps

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

Rails deleting photo gallery photos

I'm using:
Rails 4.0.1
paperclip 3.5.2
I managed to create an image gallery. With model PlaceGallery for Place model. There is no controller for PlaceGallery and i don't know how to delete this images in gallery. I mage a checkbox and etc, but when i updating places it ust duplicates missing images. What should i add to my place controller?
**place.rb**
class Place < ActiveRecord::Base
has_many :place_galleries, :dependent => :destroy
accepts_nested_attributes_for :place_galleries, :allow_destroy => true
end
**place_gallery.rb**
class PlaceGallery < ActiveRecord::Base
belongs_to :place
has_attached_file :image
end
**places_controller.rb**
class PlacesController < ApplicationController
def new
#place = Place.new
(3 - #place.place_galleries.length).times { #place.place_galleries.build }
end
def edit
#place = Place.find_by_slug!(params[:id])
(3 - #place.place_galleries.length).times { #place.place_galleries.build }
end
private
def set_place
#place = Place.find_by_slug!(params[:id])
end
def place_params
params.require(:place).permit(:title, :slug, :user_id, :place_type_id, :content, :address, :place_photo, place_galleries_attributes: :image)
end
end
**_form.html.erb** for Place
<%= f.fields_for :place_galleries do |pg| %>
<% if pg.object.new_record? %>
<%= pg.file_field :image %>
<% end %>
<% end %>
<%= f.fields_for :place_galleries do |pg| %>
<% unless pg.object.new_record? %>
<%= link_to(image_tag(pg.object.image.url(:small)), pg.object.image.url(:large))%>
<%= pg.check_box :_destroy %>
<% end %>
<% end %>
Solved my problem by adding params :id and :_destroy to my places_controller.rb
def place_params
params.require(:place).permit(:title, :slug, :user_id, :place_type_id, :content, :address, :place_photo, place_galleries_attributes: [:image, :id, :_destroy])
end
That's the answer.
If you don't know how to make an image gallery try this - http://www.emersonlackey.com/article/rails-paperclip-multiple-file-uploads and use my edits if you running rails 4.
Thanks to all. Good luck!

Ruby on Rails: create records for multiple models with one form and one submit

I have a 3 models: quote, customer, and item. Each quote has one customer and one item. I would like to create a new quote, a new customer, and a new item in their respective tables when I press the submit button. I have looked at other questions and railscasts and either they don't work for my situation or I don't know how to implement them.
quote.rb
class Quote < ActiveRecord::Base
attr_accessible :quote_number
has_one :customer
has_one :item
end
customer.rb
class Customer < ActiveRecord::Base
attr_accessible :firstname, :lastname
#unsure of what to put here
#a customer can have multiple quotes, so would i use has_many or belongs_to?
belongs_to :quote
end
item.rb
class Item < ActiveRecord::Base
attr_accessible :name, :description
#also unsure about this
#each item can also be in multiple quotes
belongs_to :quote
quotes_controller.rb
class QuotesController < ApplicationController
def index
#quote = Quote.new
#customer = Customer.new
#item = item.new
end
def create
#quote = Quote.new(params[:quote])
#quote.save
#customer = Customer.new(params[:customer])
#customer.save
#item = Item.new(params[:item])
#item.save
end
end
items_controller.rb
class ItemsController < ApplicationController
def index
end
def new
#item = Item.new
end
def create
#item = Item.new(params[:item])
#item.save
end
end
customers_controller.rb
class CustomersController < ApplicationController
def index
end
def new
#customer = Customer.new
end
def create
#customer = Customer.new(params[:customer])
#customer.save
end
end
my form for quotes/new.html.erb
<%= form_for #quote do |f| %>
<%= f.fields_for #customer do |builder| %>
<%= label_tag :firstname %>
<%= builder.text_field :firstname %>
<%= label_tag :lastname %>
<%= builder.text_field :lastname %>
<% end %>
<%= f.fields_for #item do |builder| %>
<%= label_tag :name %>
<%= builder.text_field :name %>
<%= label_tag :description %>
<%= builder.text_field :description %>
<% end %>
<%= label_tag :quote_number %>
<%= f.text_field :quote_number %>
<%= f.submit %>
<% end %>
When I try submitting that I get an error:
Can't mass-assign protected attributes: item, customer
So to try and fix it I updated the attr_accessible in quote.rb to include :item, :customer but then I get this error:
Item(#) expected, got ActiveSupport::HashWithIndifferentAccess(#)
Any help would be greatly appreciated.
To submit a form and it's associated children you need to use accepts_nested_attributes_for
To do this, you need to declare it at the model for the controller you are going to use (in your case, it looks like the Quote Controller.
class Quote < ActiveRecord::Base
attr_accessible :quote_number
has_one :customer
has_one :item
accepts_nested_attributes_for :customers, :items
end
Also, you need to make sure you declare which attributes are accessible so you avoid other mass assignment errors.
If you want add info for diferent models i suggest to apply nested_model_form like this reference: http://railscasts.com/episodes/196-nested-model-form-part-1?view=asciicast.
This solution is very simple and cleanest.

Plural for fields_for has_many association not showing in view

Currently, an Item belongs_to a Company and has_many ItemVariants.
I'm trying to use nested fields_for to add ItemVariant fields through the Item form, however using :item_variants does not display the form. It is only displayed when I use the singular.
I have check my associations and they seem to be correct, could it possibly have something to do with item being nested under Company, or am I missing something else?
Thanks in advance.
Note: Irrelevant code has been omitted from the snippets below.
EDIT: Don't know if this is relevant, but I'm using CanCan for Authentication.
routes.rb
resources :companies do
resources :items
end
item.rb
class Item < ActiveRecord::Base
attr_accessible :name, :sku, :item_type, :comments, :item_variants_attributes
# Associations
#-----------------------------------------------------------------------
belongs_to :company
belongs_to :item_type
has_many :item_variants
accepts_nested_attributes_for :item_variants, allow_destroy: true
end
item_variant.rb
class ItemVariant < ActiveRecord::Base
attr_accessible :item_id, :location_id
# Associations
#-----------------------------------------------------------------------
belongs_to :item
end
item/new.html.erb
<%= form_for [#company, #item] do |f| %>
...
...
<%= f.fields_for :item_variants do |builder| %>
<fieldset>
<%= builder.label :location_id %>
<%= builder.collection_select :location_id, #company.locations.order(:name), :id, :name, :include_blank => true %>
</fieldset>
<% end %>
...
...
<% end %>
You should prepopulate #item.item_variants with some data:
def new # in the ItemController
...
#item = Item.new
3.times { #item.item_variants.build }
...
end
Source: http://rubysource.com/complex-rails-forms-with-nested-attributes/
try this way
in your item controller new action write
def new
...
#item = # define item here
#item.item_variants.build if #item.item_variants.nil?
...
end
and in item/new.html.erb
<%= form_for #item do |f| %>
...
...
<%= f.fields_for :item_variants do |builder| %>
...
<% end %>
...
...
<% end %>
for more see video - Nested Model Form

Resources