I have a rails model 'Guitar' and a rails model 'Photo.' I wanted to be able to attach multiple photos so I watched the railscasts for Paperclip, read the docs, etc. I've used Paperclip in the past to attach a single photo, but I wanted to do multiples this time. I don't have a problem updating the model, and it doesn't error out when I attach sample photos, but when I rails console to Photos.all, nothing comes back. My ultimate goal is to a polymorphic association with an 'Amps' model, but I really just wanted to get 'Guitars' working first.
I have paperclip added to the Gemfile and I've bundle installed, restarted the server, etc. I think I'm missing something stupid and I'm new to rails so please be gentle...
guitar.rb
class Guitar < ActiveRecord::Base
belongs_to :user
has_many :photos
accepts_nested_attributes_for :photos
end
photo.rb
class Photo < ActiveRecord::Base
belongs_to :guitars
has_attached_file :photo, styles: {
thumb: '100x100>',
square: '200x200#',
medium: '300x300>',
large: '600x600#' }
end
guitars_controller.rb
class GuitarsController < ApplicationController
before_action :set_guitar, only: [:show, :edit, :update, :destroy]
# GET /guitars
# GET /guitars.json
def index
#guitars = Guitar.all
end
# GET /guitars/1
# GET /guitars/1.json
def show
end
# GET /guitars/new
def new
#guitar = Guitar.new
3.times { #guitar.photos.build }
end
# GET /guitars/1/edit
def edit
#guitar = Guitar.find(params[:id])
3.times { #guitar.photos.build }
end
# POST /guitars
# POST /guitars.json
def create
#guitar = Guitar.new(guitar_params)
#guitar.user_id = current_user.id if current_user
respond_to do |format|
if #guitar.save
format.html { redirect_to #guitar, notice: 'Guitar was successfully created.' }
format.json { render action: 'show', status: :created, location: #guitar }
else
format.html { render action: 'new' }
format.json { render json: #guitar.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /guitars/1
# PATCH/PUT /guitars/1.json
def update
respond_to do |format|
if #guitar.update(guitar_params)
format.html { redirect_to #guitar, notice: 'Guitar was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #guitar.errors, status: :unprocessable_entity }
end
end
end
# DELETE /guitars/1
# DELETE /guitars/1.json
def destroy
#guitar.destroy
respond_to do |format|
format.html { redirect_to guitars_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_guitar
#guitar = Guitar.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def guitar_params
params.require(:guitar).permit(:make, :model, :year, :color, :serial, :price, :condition, :kind, :bodykind, :frets, :one_owner, :user_id)
end
end
guitars show.html.erb
<p>
<strong>Make:</strong>
<%= #guitar.make %>
</p>
<p>
<strong>Model:</strong>
<%= #guitar.model %>
</p>
<p>
<strong>Year:</strong>
<%= #guitar.year %>
</p>
<p>
<strong>Color:</strong>
<%= #guitar.color %>
</p>
<p>
<strong>Serial:</strong>
<%= #guitar.serial %>
</p>
<p>
<strong>Price:</strong>
<%= #guitar.price %>
</p>
<p>
<strong>Condition:</strong>
<%= #guitar.condition %>
</p>
<p>
<strong>Kind:</strong>
<%= #guitar.kind %>
</p>
<p>
<strong>Bodykind:</strong>
<%= #guitar.bodykind %>
</p>
<p>
<strong>Frets:</strong>
<%= #guitar.frets %>
</p>
<p>
<strong>One owner:</strong>
<%= #guitar.one_owner %>
</p>
<p>
<strong>User:</strong>
<%= #guitar.user_id %>
</p>
<div class="thumb">
<% for asset in #guitar.photos %>
<%= link_to image_tag(photo.photos.url(:thumb)), photo.photo.url(:original) %>
<% end %>
</div>
<%= link_to 'Edit', edit_guitar_path(#guitar) %> |
<%= link_to 'Back', guitars_path %>
guitars _form.html.erb
<%= simple_form_for(#guitar, html: { class: 'form-horizontal', :multipart => true}) do |f| %>
<% if #guitar.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#guitar.errors.count, "error") %> prohibited this guitar from being saved:</h2>
<ul>
<% #guitar.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.input :make, label: 'Make of the Guitar', placeholder: 'Gibson' %>
<%= f.input :model, label: 'Model of the Guitar', placeholder: 'Les Paul' %>
<%= f.input :year, label: 'Year Made', placeholder: '1957' %>
<%= f.input :color, label: 'Color', placeholder: 'GoldTop' %>
<%= f.input :serial, label: 'Serial', placeholder: '#7-8789' %>
<%= f.input :price, label: 'Price' %>
<%= f.input :condition, label: 'Condition, 1-10' %>
<%= f.input :kind, label: 'Kind of Guitar', placeholder: '6-String-Electric' %>
<%= f.input :bodykind, label: 'Body Type', placeholder: 'Solid String Electric' %>
<%= f.input :frets, label: 'Number of Frets', placeholder: '22' %>
<%= f.input :one_owner, label: 'Original Owner' %>
<%= f.fields_for :photos do |photo| %>
<% if photo.object.new_record? %>
<%= photo.file_field :photo %>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
def guitar_params
params.require(:guitar).permit(:make, :model, :year, :color, :serial, :price, :condition, :kind, :bodykind, :frets, :one_owner, :user_id, photos_attributes: [:photo])
end
You're running into mass assignment protection which is preventing the photos from being saved. Add this line to your Guitar model:
attr_accessible :photos_attributes
in my case I need create a document.
# config/initializer/paperclip.rb
require 'paperclip/media_type_spoof_detector'
module Paperclip
class MediaTypeSpoofDetector
def spoofed?
false
end
end
end
This document is necessary create in config > initializers. If your SO is windows, you need add this line in config/environments/development.rb:
Paperclip.options[:comand_path] = "/ImageMagick-6.8.9-Q16/"
Related
I am building simple ROR app which has survey question and answers. Survey is generated using scaffolding method while question and answer are model only.
Survey.rb
class Survey < ApplicationRecord
has_many :questions
accepts_nested_attributes_for :questions, allow_destroy: true
validates :name, presence: true
end
Question.rb
class Question < ApplicationRecord
belongs_to :survey
has_many :answers
accepts_nested_attributes_for :answers
validates :question_content, presence: true
end
Answer.rb
class Answer < ApplicationRecord
belongs_to :question
end
survey_controller.rb
class SurveysController < ApplicationController
before_action :set_survey, only: [:show, :edit, :update, :destroy]
def index
#surveys = Survey.all
end
def show
#survey= Survey.find(params[:id])
end
def new
#survey = Survey.new
#questions = #survey.questions.new
#answers = #questions.answers.new
end
def edit
end
def create
#survey = Survey.new(survey_params)
Survey.create(survey_params)
respond_to do |format|
if #survey.save
format.html { redirect_to #survey, notice: 'Survey was successfully created.' }
format.json { render :show, status: :created, location: #survey }
else
format.html { render :new }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #survey.update(survey_params)
format.html { redirect_to #survey, notice: 'Survey was successfully updated.' }
format.json { render :show, status: :ok, location: #survey }
else
format.html { render :edit }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
def destroy
#survey.destroy
respond_to do |format|
format.html { redirect_to surveys_url, notice: 'Survey was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_survey
#survey = Survey.find(params[:id])
end
def survey_params
params.require(:survey).permit(:name, questions_attributes: [:id, :question_content], answers_attributes: [:id, :answer_content, :answer_type])
end
end
Survey form partial
<%= form_for(#survey) do |form| %>
<% if survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% survey.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name, id: :survey_name %>
</div>
<%= form.fields_for :questions do |builder| %>
<fieldset>
<%= builder.label :question_content, "Question" %><br/>
<%= builder.text_area :question_content %><br/>
<%= form.fields_for :answers do |f| %>
<fieldset>
<%= f.text_area :answer_type %>
<%= f.text_area :answer_content %><br/>
</fieldset>
</fieldset>
<% end %>
<%end %>
<div class="actions">
<%= form.submit %>
</div>
I want to implement question and answer in single page i.e survey. Any help will appreciated.
Problem : Unable to save answers_attributes to database but Question attributes work perfectly fine. I am probably making mistake somewhere in controller not sure.
You need to change the way you're building the answer fields, so that they're referenced as fields_for questions, not surveys. Try changing this piece of code:
<%= form.fields_for :questions do |builder| %>
<fieldset>
<%= builder.label :question_content, "Question" %><br/>
<%= builder.text_area :question_content %><br/>
<%= form.fields_for :answers do |f| %>
<fieldset>
<%= f.text_area :answer_type %>
<%= f.text_area :answer_content %><br/>
</fieldset>
</fieldset>
<% end %>
<%end %>
to this:
<%= form.fields_for :questions do |builder| %>
<fieldset>
<%= builder.label :question_content, "Question" %><br/>
<%= builder.text_area :question_content %><br/>
<%= builder.fields_for :answers do |f| %>
<fieldset>
<%= f.text_area :answer_type %>
<%= f.text_area :answer_content %><br/>
</fieldset>
<% end %>
</fieldset>
<% end %>
(Note: the meaningful change is changing form.fields_for to builder.fields_for)
I'm very new to Rails development and having a problem saving multiple images/attachments to a model. My problem is that the code below is not actually saving to the item_images table when I submit the form. I am following This Article as a guide, though it seems to be a bit out of date. I feel I'm in a little over my head at this point so I hope someone can point out what I'm missing. Thanks!
I have the following models:
item.rb
class Item < ActiveRecord::Base
has_many :item_images, :dependent => :destroy
accepts_nested_attributes_for :item_images, :reject_if => lambda { |t| t['item_image'].nil? }
end
item_image.rb
class ItemImage < ActiveRecord::Base
belongs_to :item
has_attached_file :image,
:styles => { thumb: "100x100#", small: "400x400#", large: "700x700" }
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
end
My controller looks like this:
items_controller.rb
class ItemsController < ApplicationController
before_action :set_item, only: [:show, :edit, :update, :destroy]
# GET /items
# GET /items.json
def index
#items = Item.all
end
# GET /items/1
# GET /items/1.json
def show
end
# GET /items/new
def new
#item = Item.new
4.times {#item.item_images.build}
end
# GET /items/1/edit
def edit
4.times {#item.item_images.build}
end
# POST /items
# POST /items.json
def create
#item = Item.new(item_params)
respond_to do |format|
if #item.save
format.html { redirect_to #item, notice: 'Item was successfully created.' }
format.json { render :show, status: :created, location: #item }
else
format.html { render :new }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /items/1
# PATCH/PUT /items/1.json
def update
respond_to do |format|
if #item.update(item_params)
format.html { redirect_to #item, notice: 'Item was successfully updated.' }
format.json { render :show, status: :ok, location: #item }
else
format.html { render :edit }
format.json { render json: #item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /items/1
# DELETE /items/1.json
def destroy
#item.destroy
respond_to do |format|
format.html { redirect_to items_url, notice: 'Item was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_item
#item = Item.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def item_params
params.require(:item).permit(:title, :description, :price, :available, :sort_shop, :sort_gallery, :item_type, :size)
end
end
form.html.erb
<%= form_for #item, html: { multipart: true } do |f| %>
<% if #item.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#item.errors.count, "error") %> prohibited this item from being saved:</h2>
<ul>
<% #item.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :price %><br>
<%= f.text_field :price %>
</div>
<div class="field">
<%= f.label :available %><br>
<%= f.check_box :available %>
</div>
<div class="field">
<%= f.label :sort_shop %><br>
<%= f.number_field :sort_shop %>
</div>
<div class="field">
<%= f.label :sort_gallery %><br>
<%= f.number_field :sort_gallery %>
</div>
<div class="field">
<%= f.label :item_type %><br>
<%= f.text_field :item_type %>
</div>
<div class="field">
<%= f.label :size %><br>
<%= f.text_field :size %>
</div>
<%= f.fields_for :item_images do |builder| %>
<% if builder.object.new_record? %>
<div class="field">
<%= builder.label :image, "Image File" %>
<%= builder.file_field :image %>
</div>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Try this in strong parameters in Items controller
params.require(:item).permit(:title, :description, :price, :available, :sort_shop, :sort_gallery, :item_type, :size,item_images_attributes: [:image ])
than in ItemImage.rb add this line
belongs_to :item, optional: true,
and remove this line from Item.rb
:reject_if => lambda { |t| t['item_image'].nil? }
`
If you get any error please reply
So I've got these views:
new.html.erb
<div class="booyah-box col-xs-10 col-xs-offset-1">
<h1>Expose Your Hidden Gem</h1>
<%= simple_form_for #place do |f| %>
<%= f.input :name, error: "Name is mandatory" %>
<%= f.input :address %>
<%= f.input :description %>
<br />
<%= f.submit 'Create', class: 'btn btn-primary' %>
<% end %>
</div>
edit.html.erb
<div class="booyah-box col-xs-10 col-xs-offset-1">
<h1>Edit Your Place</h1>
<%= simple_form_for #place do |f| %>
<%= f.input :name %>
<%= f.input :address %>
<%= f.input :description %>
<br />
<%= f.submit 'Update', class: 'btn btn-primary' %>
<% end %>
</div>
this model:
Place.rb
class Place < ActiveRecord::Base
belongs_to :user
has_many :comments, dependent: :destroy
has_many :photos
geocoded_by :address
after_validation :geocode
validates :name, presence: true
validates :address, presence: true
validates :description, presence: true
end
And finally, places_controller.rb (only showing create and update)
def create
#place = current_user.places.create(place_params)
if #place.save
redirect_to root_path
else
render :new
end
end
def update
#place = Place.find(params[:id])
if #place.user != current_user
return render text: 'Not Allowed', status: :forbidden
end
#place.update_attributes(place_params)
if #place.save
redirect_to root_path
else
render :edit
end
end
But, I'm trying to think DRY and want to know if there is a better way to do a validation for name address and description presence without having the same identical code in both the create and update portions of my controller? I feel like I should just be writing it once...
First, you can refactor your views to use the following structure:
# new.html.erb
<div class="booyah-box col-xs-10 col-xs-offset-1">
<h1>Expose Your Hidden Gem</h1>
<%= render 'form' %>
</div>
# edit.html.erb
<div class="booyah-box col-xs-10 col-xs-offset-1">
<h1>Edit Your Place</h1>
<%= render 'form' %>
</div>
# _form.html.erb
<%= simple_form_for #place do |f| %>
<%= f.input :name %>
<%= f.input :address %>
<%= f.input :description %>
<br />
<% submit_label = #place.new_record? ? 'Create' : 'Update' %>
<%= f.submit submit_label, class: 'btn btn-primary' %>
<% end %>
And then in your controllers you could refactor to:
def create
#place = current_user.places.new(place_params)
if #place.save
redirect_to root_path
else
render :new
end
end
def update
#place = current_user.places.find(params[:id])
#place.attributes = place_params
if #place.save
redirect_to root_path
else
render :edit
end
end
I know there is a lot questions like this before, I have following all the answer, but still mine doesn't work. please help.
survey.rb
# app/models/survey.rb
class Survey < ActiveRecord::Base
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:questions].blank? }, :allow_destroy => true
end
question.rb
# app/models/question.rb
class Question < ActiveRecord::Base
belongs_to :survey
end
surveys_controller.rb
# app/controllerss/surveys_controller.rb
def new
#survey = Survey.new
#survey.questions.build
end
def edit
end
def create
#survey = Survey.new(survey_params)
respond_to do |format|
if #survey.save
format.html { redirect_to #survey, notice: 'Survey was successfully created.' }
format.json { render :show, status: :created, location: #survey }
else
format.html { render :new }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
def survey_params
params.require(:survey).permit(:name, questions_attributes: [:id, :content, :_destroy])
end
_form.html.erb
# app/views/surveys/_form.html.erb
<%= nested_form_for #survey do |f| %>
<% if #survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% #survey.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= f.fields_for :questions do |builder| %>
<div class="field">
<%= builder.label :content, "Question" %> <br>
<%= builder.text_field :content, :rows => 3 %>
<%= builder.link_to_remove "Remove this question" %>
</div>
<% end %>
<p><%= f.link_to_add "Add a question", :questions %></p>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Help? what do I miss?
:reject_if => lambda { |a| a[:questions].blank? }
a variable is a hash of attributes which will be passed to a question record. Your question model has no questions field, hence a[:questions] is always blank and the record it is rejected. Instead, do:
:reject_if => :all_blank
i am building nested form in rails 4.I keep getting this error
my _form.html.erb as
<%= nested_form_for (#project) do |f| %>
<% if #project.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#project.errors.count, "error") %> prohibited this project from being saved:</h2>
<ul>
<% #project.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= f.fields_for :questions do |builder| %>
<%= render "question_fields", :f => builder %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
_question.html.erb
<p>
<%= f.label :content, "Question" %><br />
<%= f.text_area :content, :rows => 3 %><br />
<%= f.label :subject, "Question" %><br />
<%= f.text_field :subject %><br />
<%= f.link_to_remove "Remove this task" %>
<p><%= f.link_to_add "Add a questions",:questions %></p>
</p>
project.rb
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
Edit
question.rb
class Question < ActiveRecord::Base
belongs_to :project
end
projects controller
def new
#project = Project.new
3.times do
question = #project.questions.build
end
def project_params
params.require(:project).permit(:name)
end
def create
#project = Project.new(project_params)
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render :show, status: :created, location: #project }
else
format.html { render :new }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
I used "nested_form" gem Gives Error Invalid association. Make sure that accepts_nested_attributes_for is used for :questions association.
pls help me to get rid of this error
questions controller def:-
def question_params
params.require(:question).permit(:project_id, :subject, :content)
end
Might be your problem is with your strong parameters
Try changing your project_params in your projects_controller as
def project_params
params.require(:project).permit(:name,questions_attributes: [:project_id,:subject,:content])
end
And also,your controller code should look like this
def new
#project = Project.new
3.times do
#question = #project.questions.build
end
end
def create
#project = Project.new(project_params)
respond_to do |format|
if #project.save
format.html { redirect_to #project, notice: 'Project was successfully created.' }
format.json { render :show, status: :created, location: #project }
else
format.html { render :new }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
private
def project_params
params.require(:project).permit(:name,questions_attributes: [:project_id,:subject,:content])
end
Also,you have to look for Strong Parameters with accepts_nested_attributes_for.
Update
Try changing your _form.html.erb as
<%= nested_form_for(#project) do |f| %>
<% if #project.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#project.errors.count, "error") %> prohibited this project from being saved:</h2>
<ul>
<% #project.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= f.fields_for :questions do |builder| %>
<%= render "question_fields", :ff => builder %> #changed to ff to avoid confusion
<% end %>
<p><%= f.link_to_add "Add a questions",:questions %></p> #this line it should be here.
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And your _question_fields.html.erb as
<p>
<%= ff.label :content, "Question" %><br />
<%= ff.text_area :content, :rows => 3 %><br />
<%= ff.label :subject, "Question" %><br />
<%= ff.text_field :subject %><br />
<%= ff.link_to_remove "Remove this task" %>
</p>