rails paperclip - trouble uploading multiple images to one model through nested model - ruby-on-rails

I have been trying to figure out how to upload multiple images to one model through a nested model for a while now with no luck. I have a Project model, and for each project i would like to upload multiple images. I created a model called Picture and nested it within the Project model, and have set up paperclip and everything seems fine except when I upload an image and click on "Create project", the image does not show on the "show" page. There is no error message displayed. Please help as I do not know how to proceed from here.
here is my code:
Project form:
<%= bootstrap_nested_form_for #project, :html => {:multipart => true} do |f| %>
<% f.fields_for :pictures do |builder| %>
<% if builder.object.new_record? %>
<p>
<%= builder.file_field :image %>
</p>
<% end %>
<%= builder.link_to_remove "Remove" %>
<% end %>
<p>
<%= f.link_to_add "Add Images", :pictures %>
</p>
<%= f.submit %>
<% end %>
Project controller:-
class ProjectsController < ApplicationController
before_action :set_project, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#projects = Project.all
respond_with(#projects)
end
def show
respond_with(#project)
end
def new
#project = Project.new
#project.pictures.build
respond_with(#project)
end
def edit
#project = Project.find(params[:id])
#project.pictures.build
end
def create
#project = Project.new(project_params)
if #project.save
flash[:notice] = "Successfully created project."
redirect_to #project
else
render :action => 'new'
end
end
def update
#project.update(project_params)
respond_with(#project)
end
def destroy
#project.destroy
respond_with(#project)
end
private
def set_project
#project = Project.find(params[:id])
end
def project_params
params.require(:project).permit(:id, :title, :description, :status, :phase, :location, pictures_attributes: [:id, :image])
end
end
Projects model:-
class Project < ActiveRecord::Base
has_many :pictures, :dependent => :destroy
accepts_nested_attributes_for :pictures, :reject_if => lambda { |t| t['picture'].nil? }
end
Pictures model:-
class Picture < ActiveRecord::Base
belongs_to :project
has_one :image
has_attached_file :image,
:path => ":rails_root/public/system/:attachment/:id/:style/:filename",
:url => "/system/:attachment/:id/:style/:filename",
:styles => { :medium => "300x300>", :thumb => "100x100>" }
validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
end
Show page:-
<% #project.pictures do |picture| %>
<%= image_tag picture.image_url %>
<% end %>
<p>
<strong>Title:</strong>
<%= #project.title %>
</p>
<p>
<strong>Description:</strong>
<%= #project.description %>
</p>
<p>
<strong>Status:</strong>
<%= #project.status %>
</p>
<p>
<strong>Phase:</strong>
<%= #project.phase %>
</p>
<p>
<strong>Location:</strong>
<%= #project.location %>
</p>
<%= link_to 'Edit', edit_project_path(#project) %> |
<%= link_to 'Back', projects_path %>
schema :-
ActiveRecord::Schema.define(version: 20150728092717) do
create_table "pictures", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.integer "project_id"
end
add_index "pictures", ["project_id"], name: "index_pictures_on_project_id"
create_table "projects", force: true do |t|
t.string "title"
t.text "description"
t.string "status"
t.string "phase"
t.string "location"
t.datetime "created_at"
t.datetime "updated_at"
end

Your form and whitelist uses the property name image.
But you are rejecting any nested pictures if they don't have the picture param.
accepts_nested_attributes_for :pictures, :reject_if => lambda { |t| t['picture'].nil? }
Nested attributes params are not wrapped in a "model key" like rails form params usually are. This is what they look like:
params = {
project: {
pictures_attributes: [
{
image: 'foo.jpg'
}
]
}
}
You can catch these kind of errors quite simply with model specs:
require 'rails_helper'
RSpec.describe Project do
it 'accepts nested pictures' do
project = Project.new(pictures_attributes: [{ image: 'foo.jpg' }])
expect(project.pictures.first).to to_be_a Picture
end
end

Related

Could not save nested form in rails 5.1

I used nested_form gem and I am trying to build a form which has fields from two tables(Project, Question).
My model:
class Project < ApplicationRecord
has_many :questions
accepts_nested_attributes_for :questions
end
class Question < ApplicationRecord
belongs_to :project
end
My controller:
class ProjectsController < ApplicationController
layout 'application'
def index
#projects = Project.all
end
def show
#project = Project.find(params[:id])
end
def new
#project = Project.new
#questions = #project.questions.build
end
def create
#project = Project.new(project_params)
#project.save
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, question_attributes: [:id, :content, :_delete])
end
end
My view:
<%= 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 %>
<% end %>
<p>
<%= f.link_to_add "Add a questions",:questions %>
</p>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And my schema file :
create_table "projects", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "questions", force: :cascade do |t|
t.integer "project_id"
t.string "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["project_id"], name: "index_questions_on_project_id", using: :btree
end
And _question_fields file is :
<p>
<%= ff.label :content, "Question" %>
<%= ff.text_area :content%>
<%= ff.link_to_remove "Remove this task"%>
</p>
Table Project will be saved but the table Question could not be saved.Why?
After change this line of code
def project_params
params.require(:project).permit(:name, questions_attributes: [:id, :content, :_delete])
end
I get the following error:
1 error prohibited this project from being saved:
Questions project must exist
I applied the change too ,but this time nothing could not be saved.
def project_params
params.require(:project).permit(:name, questions_attributes: [:id, :content, :project_id, :_delete])
end
The issue is with the project_params. As you have has_many :questions, the question_attributes should be changed to questions_attributes
def project_params
params.require(:project).permit(:name, questions_attributes: [:id, :content, :_delete])
end
Update:
Questions project must exist
Either permit project_id in questions_attributes
def project_params
params.require(:project).permit(:name, questions_attributes: [:id, :content, :project_id, :_delete])
end
or set optional: true on the association
class Question < ApplicationRecord
belongs_to :project, optional: true
end

Rails Not able to save data, association

I'm doing a parking permit website. The problem I met is that I'm not able to save my data to the PERMIT database which associated with the USER database. The problem i think is I didn't bring the user to the permit(Maybe i missed something). I found out the error when I trying to save from Permit.errors.full_messages is ["User must exist"]. Any help is appreciated, Thank you!
Schema.rb
ActiveRecord::Schema.define(version: 20160920143651) do
create_table "permits", force: :cascade do |t|
t.string "vehicle_type"
t.string "name"
t.string "studentid"
t.string "department"
t.string "carplate"
t.string "duration"
t.date "permitstart"
t.date "permitend"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_permits_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.integer "user_type"
end
end
Create_permit.rb
class CreatePermits < ActiveRecord::Migration[5.0]
def change
create_table :permits do |t|
t.string :vehicle_type
t.string :name
t.string :studentid
t.string :department
t.string :carplate
t.string :duration
t.date :permitstart
t.date :permitend
t.references :user, foreign_key: true
t.timestamps
end
add_index :permits, :user_id
end
end
Permit_controller
class PermitsController < ApplicationController
before_action :set_permit, only: [:show, :destroy]
def index
#permits = Permit.all
end
def new
#permits = Permit.new
end
def create
#permits = Permit.new(permit_params)
if #permits.save
redirect_to #permits
else
redirect_to contact_path
end
end
def destroy
Permit.destroy_all(user_id: 1)
respond_to do |format|
format.html { redirect_to users_url, notice: 'Permit was successfully canceled.' }
format.json { head :no_content }
end
end
def show
#permits = Permit.find(params[:id])
end
def update
respond_to do |format|
if #permits.update(user_params)
format.html { redirect_to #user, notice: 'Permit was successfully updated.' }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_permit
#permits = Permit.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def permit_params
params.require(:permit).permit(:vehicle_type, :name, :studentid, :department, :carplate, :duration, :permitstart, :permitend)
end
end
user.rb
class User < ApplicationRecord
has_many :permits
has_secure_password
end
Permit.rb
class Permit < ApplicationRecord
belongs_to :user
end
permit/new.html.erb
<% provide(:title, 'New Permit') %>
<h1>Permit Application</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#permits) do |f| %>
<%= f.label :"Vehicle" %>
<%= f.text_field :vehicle_type, class: 'form-control' %>
<%= f.label :"License Plate" %>
<%= f.text_field :carplate, class: 'form-control' %>
<%= f.label :"Student ID" %>
<%= f.text_field :studentid, class: 'form-control' %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :"Department of applicant" %>
<%= f.text_field :department, class: 'form-control' %>
<%= f.label :permit_start %>
<%= f.date_select :permitstart, class: 'form-control' %>
<%= f.label :permit_end %>
<%= f.date_select :permitend, class: 'form-control' %>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
</div>
</div>
I guess you are using Rails 5. The problem is you have belongs_to association on permit that is belongs to user but while creating permit you are not associating any user with it and in Rails 5 it is mandatory to assign data to belongs_to association i.e you can not save permit when it don't have user_id so try to assign a user_id to permit. refer this for change to rails 5 belongs_to association
Where exactly is your error ? If in update action, you have to change your before_action. You must add there :update action.
before_action :set_permit, only: [:show, :destroy, :update]

Nested form fields not showing in polymorphic association

Hi I have a polymorphic association with for a Document model for storing document uploads. I'm trying to submit the document attributes as a nested attribute via the associated model.
However, when I load the form, the nested field does not show. What am I missing?
Schema:
create_table "documents", force: :cascade do |t|
t.json "links"
t.integer "linkable_id"
t.string "linkable_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "documents", ["linkable_type", "linkable_id"], name: "index_documents_on_linkable_type_and_linkable_id", using: :btree
Models:
class Document < ActiveRecord::Base
belongs_to :linkable, polymorphic: true
belongs_to :user
belongs_to :company
mount_uploaders :links, DocUploader
end
class CustomerPlan < ActiveRecord::Base
has_many :documents, as: :linkable
accepts_nested_attributes_for :documents
end
Controller:
class CustomerPlanController < ApplicationController
def new
#customer_plan = current_company.customer_plans.build
end
def create
#customer_plan = current_company.customer_plans.build(customer_plan_params)
if #customer_plan.save
redirect_to #customer_plan, notice: 'Customer plan was successfully created.'
else
render :new
end
end
private
def cusomter_plan_params
params.require(:cusomter_plan_params).permit(:date, :name, :plan_type,
documents_attributes: [:id, links: []])
end
end
Form:
<%= simple_nested_form_for #stock_plan, :html => { :multipart => true } do |f| %>
<%= f.error_notification %>
<%= f.input :date %>
<%= f.input :name %>
<%= f.input :plan_type %>
<%= f.simple_fields_for :documents do |d| %>
<p><b>Upload here:</b></p>
<%= d.file_field :links, multiple: true %>
<br>
<% end %>
<%= f.button :submit%>
<% end %>

Uploading Multiple Images With Paperclip - Rails 4 App

I have been through many tutorial and questions here but none seem to help me - it may be because I am new to this. The one that most closely aligns is here but still it hasn't helped me figure this out.
I am trying to upload multiple pictures with paperclip. (I have the mini_magick gem as well) I have succeeded in creating a section for a "Profile Image" using this gem but now I need a section with multiple pictures. Any help would be great. Currently no images are showing when I upload them in the product show view nor saving to a product in the database.
Product table schema
create_table "products", force: true do |t|
t.string "name"
t.text "description"
t.decimal "price"
t.datetime "created_at"
t.datetime "updated_at"
t.date "releasing_on"
t.string "website"
t.string "image_file_name"
t.string "industry"
t.string "slug"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.string "company"
t.string "picture_file_name"
t.string "picture_content_type"
t.integer "picture_file_size"
t.datetime "picture_updated_at"
end
(Product Contoller) products_controller.rb
class ProductsController < ApplicationController
before_action :require_signin
before_action :require_admin, except: [:index, :show]
before_action :set_product, only: [:show, :edit, :update, :destroy]
def show
#clockers = #product.clockers
#categories = #product.categories
if current_user
#current_clock = current_user.clocks.find_by(product_id: #product.id)
end
end
def edit
end
def update
if #product.update(product_params)
redirect_to #product
else
render :edit
end
end
def new
#product = Product.new
end
private
def product_params
params.require(:product).permit(:slug, :name, :description, :price, :releasing_on, :website, :company, :image, :image_content_type, :picture, :picture_content_type, category_ids: [])
end
def set_product
#product = Product.find_by!(slug: params[:id])
end
end
(Product Model) product.rb
class Product < ActiveRecord::Base
before_validation :generate_slug
...
has_attached_file :image
has_attached_file :picture
...
end
products.helper.rb (Products Helper)
module ProductsHelper
...
def image_for(product)
if product.image.exists?
image_tag(product.image.url)
else
image_tag('placeholder_sneaker.png')
end
end
def picture_for(product)
if product.picture.exists?
image_tag(product.picture.url)
else
""
end
end
end
Products -- show.html.erb (Where I'd like to show the pictures)
<h1> <%= #product.name %></h1>
<div class="container">
<div class="row">
<div class="col-md-4 thumb">
<div class="thumbnail" >
<img class="img-responsive"> <%= image_for(#product) %> <%# profile image %>
<div>
<%= picture_for(#product) %> <%# multiple pictures %>
</div>
</div>
</div>
_form.html.erb (Product Show/Edit/Update Form)
<%= form_for(#product) do |f| %>
<%= render "shared/errors", object: #product %>
<form class="form-horizontal" role="form">
<div class="form-group">
<ol>
<li class=>
<%= f.label :image, "Profile Image" %>
<%= f.file_field :image %>
</li>
<li class=>
<%= f.label :picture, "More Pictures" %>
<%= f.file_field :picture, multiple: true %>
</li>
</ol>

SQLite3::SQLException: no such column: problem with association and show view

I am getting the following error message on the view : http://localhost:3000/microposts/2
SQLite3::SQLException: no such column: answers.micropost_id: SELECT "answers".* FROM "answers" WHERE ("answers".micropost_id = 2)
Here are my migrations:
| db > migration > create micropost |
class CreateMicroposts < ActiveRecord::Migration
def self.up
create_table :microposts do |t|
t.string :content
t.timestamps
end
end
def self.down
drop_table :microposts
end
end
| db > migration > create answer |
class CreateAnswers < ActiveRecord::Migration
def self.up
create_table :answers do |t|
t.string :location
t.text :body
t.references :micropost
t.integer :micropost_id
t.timestamps
end
end
def self.down
drop_table :answers
end
end
The Answer Controler :
def create
#answer = Answer.new(params[:answer])
#answer.micropost = #micropost; #answer.save && #micropost.save
redirect_to micropost_path(#micropost)
respond_to do |format|
if #answer.save
format.html { redirect_to(#answer, :notice => 'Answer was successfully created.') }
format.xml { render :xml => #answer, :status => :created, :location => #answer }
else
format.html { render :action => "new" }
format.xml { render :xml => #answer.errors, :status => :unprocessable_entity }
end
end
end
and the View:
<p id="notice"><%= notice %></p>
<p>
<b>Content:</b>
<%= #micropost.content %>
<h2>Location Answers:</h2>
<% #micropost.answers.each do |answer| %>
<p>
<b>Answer:</b>
<%= answer.body%>
</p>
<%end %>
<h2> Answer a location:</h2>
<%= form_for ([#micropost, #micropost.answers.build]) do |f| %>
<div class="field">
<%= f.label :location %><br />
<%= f.text_field :location %>
</div>
<div class="field">
<%= f.label :body %><br/>
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
</p>
<%= link_to 'Edit', edit_micropost_path(#micropost) %> |
<%= link_to 'Back', microposts_path %>
I cannot find what's wrong in this application.
- I tried to rollback and migrate again it didn't work.
- I tried to manually add the "t.integer :micropost_id" in the migration it didn't work
My model have the association 'belongs_to" and "has_many" and I added "
resources :microposts do
resources :answers
end
to my config.rb file.
I believe the has_many association requires a relationship table to join against. If you had has_one and belongs_to (a one to one association) works with the simple _id column approach but has_many won't. So if you put this join table in and describe the has_many through it, you should get what you want.
Here's a really great guide for rails associations that I use when this stuff becomes unclear to me.
You don't need to set micropost_id in your migration. This is done by t.references
create_table :answers do |t|
t.string :location
t.text :body
t.references :micropost
t.timestamps
end
Best practice to set and index, for example:
add_index :answers, :micropost_id

Resources