Im following this tutorial: https://www.devwalks.com/lets-build-instagram-in-rails-part-1/
To create a version of instagram. When I upload an image, add a caption and submit, it will redirect to the index page as expected but the data doesnt seem to have been saved. When I open the rails console and try to get the posts with Posts.first, it returns nil.
Controller:
class PostsController < ApplicationController
def index
end
def new
#post = Post.new
end
def create
#post =Post.create(post_params)
#post.save
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:image, :caption)
end
end
Model:
class Post < ActiveRecord::Base
validates :image, presence: true
has_attached_file :image, styles: { :medium => "640x"}
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
end
form:
<%= simple_form_for #post do |f| %>
<%= f.input :image %>
<%= f.input :caption %>
<%= f.button :submit %>
<% end %>
routes:
resources :posts
root 'posts#index'
Appreciate any ideas.
Thanks
I see a few problems here:
create will save so you don't need another #post.save.
create returns the new Post object, but you have to check if it has been saved successfully or not (via #post.persisted, or via if #post.save).
From 1 & 2, I believe your post was not saved, due to validation on image presence.
Now why it's happening? I guess your form has no multipart/form-data set that the image file was not submitted at all.
To add that to simple_form (paperclip README) :
<%= simple_form_for #post, html: { multipart: true } do |f| %>
Related
I am using the Paperclip gem. A user can submit a location with an image. I do not want the user to duplicate an already submitted location, but they can add an image to it.
I have been trying to figure it out. I will leave the important code below:
location.rb
class Location < ApplicationRecord
has_many :submissions
has_many :users, through: :submissions
# Allows submission objects
accepts_nested_attributes_for :submissions
submission.rb
class Submission < ApplicationRecord
belongs_to :user
belongs_to :location
has_attached_file :image, styles: { large: "600x600>", medium: "300x300>", thumb: "150x150#" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
locations_controller.rb
class LocationsController < ApplicationController
# Before actions get routed and ran, find_location will occur
before_action :find_location, only: [:show, :edit, :update, :destroy]
# For the Locations/index.html.erb
def index
#locations = Location.all
end
# Binds submission object to the form in new.html.erb
def new
#locations = Location.new
#locations.submissions.build
end
# For creating a new location in the new.html.erb form
def create
#locations = Location.new(user_params)
# Everything went well. User will be sent to #locations show page
if #locations.save
# Redirects to user submitted locations
redirect_to #locations
else
render 'new'
end
end
# Finds new location user submitted by its unique id
def show
end
# Allowing user to update their submitted location
def edit
end
# Updates users edited submission
def update
if #locations.update(user_params)
# Redirects to user submitted locations
redirect_to #locations
else
render 'edit'
end
end
# Deletes users submission
def destroy
#locations.destroy
# Redirects to user submitted locations
redirect_to #locations
end
private
# Used for finding user submitted location (Prevents DRY)
def find_location
#locations = Location.find(params[:id])
end
# Strong parameters for security - Defines what can be update/created in location model
def user_params
params.require(:location).permit(:city, :state, :submissions_attributes => [:image])
end
end
_form.html.erb
<%= form_for #locations, html: {multipart: true} do |f| %>
.
.
.
<!-- User enters image-->
<%= f.fields_for :submissions do |s| %>
<div class="form-group">
<h3>Upload Image:</h3>
<%= s.file_field :image, class: 'form-control' %>
</div>
<% end %>
<% end %>
show.html.erb
<h3>Image: <%= image_tag #locations.image.url(:medium) %></h3>
I get an error:
"undefined method `image' for.."
It looks like you're trying to do form tags for collections of records, which I don't think will work. Instead, I think you need a structure something like:
<% #locations.each do |location| %>
<%= form_for location, html: {multipart: true} do |f| %>
.
.
.
<!-- User enters image-->
<%= f.fields_for location.submissions.new do |s| %>
<div class="form-group">
<h3>Upload Image:</h3>
<%= s.file_field :image, class: 'form-control' %>
</div>
<% end %>
<% end %>
both the form_for and fields_for need to point to a singular resource.
Side note: Paperclip has been deprecated, and it is recommended that you instead use the Rails internal ActiveStorage.
i just started to do a sample webpage in ruby on rails.
i am getting an error "Post model missing required attr_accessor for 'image_file_name'" when i tried to post the image from a form.
my code is
routes.rb
Rails.application.routes.draw do
resources :posts
root 'posts#index'
end
posts_controll.rb
class PostsController < ApplicationController
def index
end
def new
#post = Post.new
end
def create
#post = Post.create(post_params)
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:image, :caption)
end
end
newhtml.erb
<%= simple_form_for #post do |f| %>
<%= f.input :image %>
<%= f.input :caption %>
<%= f.button :submit %>
<% end %>
post.rb
class Post < ActiveRecord::Base
validates :image, presence: true
has_attached_file :image, styles: { :medium => "640x" }
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
end
i didnt understand the error here. i think i have done all right.
please help me guys .
This question already has answers here:
form_for with nested resources
(3 answers)
Closed 7 years ago.
simple question that I am not able to solve some how.
I am trying to mimic the first few steps of this Railscast Episode. I have a picture-Model and I am trying to instantiate an object of this kind on the index page. Therefor I am using those lines:
index.erb.html
<%= form_for Picture.new do |f| %>
<%= f.label :image, "Upload" %>
<%= f.file_field :image, multiple: true %>
<% end %>
But I am getting this error:
undefined method `pictures_path' for #<#<Class:0xb465af0>:0x58fc488>
If I remove the form it works perfectly. Seems simple but I can't solve it. I would appreciate some help.
PicturesController
class PicturesController < ApplicationController
respond_to :html
def index
#house = House.find(params[:house_id])
#pictures = #house.pictures
respond_with(#pictures)
end
def new
#picture = Picture.new
end
def create
end
def destroy
end
private
def picture_params
params.require(:picture).permit(:id, :name, :house_id, :image, :_destroy)
end
routes.rb
Rails.application.routes.draw do
resources :houses do
resources :pictures, only: [:index]
end
end
With your given routes info, you don't really have pictures_path. You have only these routes (if you do a rake routes):
house_pictures GET /houses/:house_id/pictures(.:format) pictures#index
houses GET /houses(.:format) houses#index
That's why you are getting that error.
You have access to house_pictures_path BUT NOT pictures_path.
To solve this issue, you have to use house_pictures_path and send the #house and #pictures as argument to that. something like this:
<%= form_for [#house, #house.pictures.build] do |f| %>
<%= f.label :image, "Upload" %>
<%= f.file_field :image, multiple: true %>
<% end %>
Your pictures resource is nested within your houses resource. There is no route to allow you to create a new Picture without a House to provide the surrounding context, and so form_for cannot automatically produce a URL if you give it only Picture.new.
You need to give it both a house, and a picture.
Typically, your would do something like this:
form_for [#house, #house.pictures.new] do |f|
I am developing a website in ruby on rails. I want to upload multiple images while creating post using paperclip. I could not find any images being uploaded into the public folder and hence images are not getting displayed when I create new post. I have created a model called Postimage.rb for images and referenced to already existing model "post".I have used paperclip to upload single image in other models and it is working fine.
rails g model postimage post:references caption:string
rails g paperclip post_images photo
Here is the Postimage.rb
class Postimage < ActiveRecord::Base
belongs_to :post
has_attached_file :photo,
:styles => {:small => "100x100>", :medium => "640x480>"}
validates_attachment_content_type :photo, :content_type => /\Aimage\/.*\Z/
end
And in the Post model,
class Post < ActiveRecord::Base
has_many :postimages
accepts_nested_attributes_for :postimages, :allow_destroy => true, :reject_if => lambda { |t| t[:postimage].nil? }
Here is the code in post controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#posts = Post.all.order('created_at DESC').paginate(page: params[:page],:per_page =>7)
#users = User.all
respond_with(#posts)
end
def show
respond_with(#post)
end
def new
#post = Post.new
5.times {#post.postimages.build} # added this
respond_with(#post)
end
def edit
5.times{#post.postimages.build} # ... and this
end
def create
#post = current_user.posts.build(post_params)
#post.user_id = current_user.id
if #post.save
redirect_to #post, :notice =>"Post created successfully!!"
else
render "new"
end
end
def update
#post.update(post_params)
respond_with(#post)
end
def destroy
#post.destroy
redirect_to preschools_Home_path
#respond_with(#post)
end
private
def set_post
#post = Post.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :content, postimages_attributes: [:caption, :photo])
end
Here is the code in _form.html in posts
<%= form_for(#post, :html =>{:multipart => true }) do |f| %>
<%=f.fields_for :postimages do |builder| %>
<%if builder.object.new_record? %>
<p>
<%= builder.label :caption, "Image Caption" %>
<%= builder.text_field :caption %>
</p>
<p>
<%= builder.label :photo, "Image File" %>
<%= builder.file_field :photo %>
</p>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Here is the code in show.html.erb in posts
<div>
<% #post.postimages.each do |postimage|%>
<%= image_tag (postimage.photo.url(:medium))%>
<% end %>
</div>
Can you please help me. Thanks.
I have added image column to post model. And that image is getting displayed. But in the case of multiple upload, it is not working.
Logs code below might help.
Parameters: {"utf8"=>"✓", "authenticity_token"=>"PHcPmsB+a0qy6tn4U/nRyycjGFYHiFuum7LNqO8EX24+mGq+Yu7Ct0Ls/odNyAjUtVkT1cMImYRYwnpVajQRXA==", "post"=>{"title"=>"1st post", "content"=>"Added image", "postimages_attributes"=>{"0"=>{"caption"=>"1st image", "photo"=>#<ActionDispatch::Http::UploadedFile:0x007f4a351b0ba8 #tempfile=#<Tempfile:/home/ubuntu/workspace/website/RackMultipart20150715-1790-7hfszv.jpg>, #original_filename="Murali.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"post[postimages_attributes][0][photo]\"; filename=\"Murali.jpg\"\r\nContent-Type: image/jpeg\r\n">}
The solution provided below works with Paperclip as well:
Rails 4 multiple image or file upload using carrierwave
Only difference would be in post_attachment.rb
Instead of:
class PostAttachment < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
belongs_to :post
end
You would have
class PostAttachment < ActiveRecord::Base
belongs_to :post
has_attached_file :avatar, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\Z/
end
I am looking for a solution to give the user the ability to upload multiple images through one file_field. I have looked in to options such a Jquery File Upload and Uploadify but have yet to come across good examples with a working solution.
I already have multiple images setup,
has_attached_file :asset,
:styles => { :large => "640x480", :medium => "300x300", :thumb => "100x100" },
:storage => :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml",
:path => "/:contributor_id/:listing_name/:filename"
Right now I am displaying 5 individual file_fields
def new
#listing = Listing.new
5.times {#listing.assets.build }
respond_to do |format|
format.html # new.html.erb
format.json { render json: #listing }
end
end
I would like to have
<%= f.file_field :asset, :multiple => true %>
That allows the user to select multiple files in their file browser. But how can I process these with a nested model? And get them to upload.
So there are a few issues here.
First, Paperclip's has_attached_file method isn't an association to many files. It looks like you're trying to build an "asset" as if it's a Rails association. All Paperclip does is put a couple of fields into your table to store some meta-data about the file and you get one attached file per declaration of has_attached_file. If you want to attach 5 files, you would need to do something like:
has_attached_file :asset1
has_attached_file :asset2
has_attached_file :asset3
has_attached_file :asset4
has_attached_file :asset5
OR, alternatively, you could create another model just to store the files. For example:
class Listing < ActiveRecord::Base
has_many :assets
end
class Asset < ActiveRecord::Base
belongs_to :listing
has_attached_file :picture
end
That way, you could have multiple assets attached to one listing (you didn't say what the original object was so I just called it "listing").
Second, there is no such thing as a multiple file upload in HTML (and, as such, the file_field method doesn't take a :multiple => true argument. You'll have to use something beyond Rails built-in form handling if you want multiple-file upload. Uploadify is a decent choice (that I've used before). There is a gem that will transform file fields to use uploadify (and will support the :multiple => true syntax that you want): https://github.com/mateomurphy/uploadify_rails3/wiki. However, I cannot vouch for how good it is.
My advice would be to start step-by-step. Uploading via Flash to Rails can be a complicated process that involves dealing with the CSRF meta-tag and other fields in your form. Start by making a form that allows a user to upload one file and stores it through Paperclip. Then maybe break the has_attached_file declaration into another model so that you can have 1 or many files associated with a model (as shown in the multi-model code block above). Then try adding Uploadify or another alternative. Ernie Miller has a decent tutorial on integrating Uploadify: http://erniemiller.org/2010/07/09/uploadify-and-rails-3/.
To start, remember that has_attached_file can only attach one file. When you try calling #listing.assets there is no "assets". There is an asset. You need to create a separate model yourself and use Rails' associations if you want multiple files.
Accepted answer says there is no such thing as a multiple file upload in HTML.
<%= f.file_field :files, multiple: true %>
This allows you to select multiple images and send them as an array.
If you have the relationship Dog has_many Images and Image has_attachment :file, do this to get multiple images to upload at once:
In your html.erb
<%= form_for #dog, html: { multipart: true } do |f| %>
<%= f.file_field :files, accept: 'image/png,image/jpeg,image/gif', multiple: true %>
<%= end %>
In your controller
def dog_params
params.require(:dog).permit files: []
end
In your Dog model
def files=(array = [])
array.each do |f|
images.create file: f
end
end
This is assuming you're already able to upload one image but want to upgrade to multiple images at once. Notice that wait time will increase.
To help reduce wait time, peep my post on this question related to speed uploading.
Here is a full example of multiple file uploads. Here a user has_many uploads. Each upload model has an avatar which represents the file attachment. Ultimately: we are creating many uploads when we create the user.
The Models
#models/user.rb
class User < ApplicationRecord
has_many :uploads
def files=(array_of_files = [])
array_of_files.each do |f|
uploads.build(avatar: f, user: self)
end
end
end
#models/upload.rb
class Upload < ApplicationRecord
belongs_to :user
has_attached_file :avatar
validates_attachment_content_type :avatar, :content_type => ["image/png"]
end
The form:
# views/users/_form.html.erb
<%= form_with(model: user, local: true) do |form| %>
...
<div class="field">
<%= form.file_field :files, multiple: true %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
The Controller
class UsersController < ApplicationController
before_action :set_user, only: [:show]
def show
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to #user, notice: 'User was successfully created.'
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:name, files: [])
end
end
User#show
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= #user.name %>
</p>
<h3>Uploads</h3>
<div>
<% #user.uploads.each do |upload| %>
<div>
<%= link_to upload.avatar.url do%>
<%= upload.avatar_file_name %>
<% end %>
</div>
<% end %>
</div>
<%= link_to 'Edit', edit_user_path(#user) %> |
<%= link_to 'Back', users_path %>