Upload base64 Image with Paperclip - Rails 4 - ruby-on-rails

I am relatively new to Rails and would appreciate any help.
My website accepts a signature image in base64 format and I am trying to use a Paperclip adaptor to decode the image and save it to my form model as the :signature attribute. I am using the advice given here (and here) which advises to use the following code:
In model:
class Thing
has_attached_file :image
In controller:
def create
image = Paperclip.io_adapters.for(params[:thumbnail_data])
image.original_filename = "something.gif"
Thing.create!(image: image)
...
end
My assumption is that Thing.create! is setting the value of Paperclip's model attribute :image to be the value of the image variable whilst creating and saving a new Thing object. I tried to implement the same code in my FormsController (create action) before #form.save, but am receiving this error:
undefined method `before_image_post_process' for #<Class:0x007f94a2a26de8>
My FormsController:
class FormsController < ApplicationController
before_action :logged_in_user
before_action :admin_user, only: :destroy
def index
#forms = Form.all #paginate
end
def show
#form = Form.find(params[:id])
end
def new
#form = Form.new
end
def create
#form = Form.new(form_params)
# Paperclip adaptor
signature = Paperclip.io_adapters.for(params[:base64])
signature.original_filename = "something.png"
# Attempt to submit image through Paperclip
#form.signature = signature
if #form.save
flash[:success] = "The form has been successfully created!"
redirect_to #form
else
render 'new'
end
end
def edit
#form = Form.find(params[:id])
end
def update
#form = Form.find(params[:id])
if #form.update_attributes(form_params)
flash[:success] = "Form has been updated!"
redirect_to #form
else
render 'edit'
end
end
def destroy
Form.find(params[:id]).destroy
flash[:success] = "Form deleted"
redirect_to forms_path
end
private
def form_params
params.require(:form).permit(:first_name, :last_name, :email, :phone, :address, :member_type, :base64)
end
end
This is my Form model:
class Form < ActiveRecord::Base
has_attached_file :signature
validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
end

Assuming that you're using the Rails form helpers over in your view, and based on your form_params list, the :base64 key won't be at the top level of your params hash, but rather one level down at params[:form][:base64]

Related

Proper model set up

I am new to stackoverflow, so my apologies if this is formatted poorly.
In my current project I have a model Driver, which has many trips. Those trips have many mileages, backhauls, picks, drops and hours. When I create a new trip, i want to be able to associate it to the driver, but I also want to be able to add the mileages, backhauls, picks and drops and hours on the same page. I am unsure how to structure my routes for this. I have been successful in creating a trip for a driver without adding on the additional models to the trip but from there I am stumped. I have only created the mileage model/controller so far for what needs to be associated with the trip. Any nudge in the right direction would be greatly appreciated.
Driver Model
class Driver < ApplicationRecord
has_many :trips
end
Trip Model
class Trip < ApplicationRecord
belongs_to :driver
has_many :mileages
accepts_nested_attributes_for :mileages
default_scope {order(date: :asc)}
validates :total, presence: true
validates :date, presence: true
validates_uniqueness_of :trip_number, :allow_nil => true, :allow_blank =>
true
end
Mileage Model
class Mileage < ApplicationRecord
belongs_to :trip
end
Trips controller
def index
#trips = Trip.all
end
def show
end
def new
#driver = Driver.find(params[:driver_id])
#trip = Trip.new
end
def edit
end
def create
#driver = Driver.find(params[:driver_id])
#trip = Trip.new(trip_params)
#driver.trips.create(trip_params)
respond_to do |format|
if #driver.trips.create(trip_params)
flash[:notice] = "Trip successfully created"
redirect_to new_driver_trip_path(#driver)
else
flash[:warning] = "Unable to create trip"
redirect_to new_driver_trip_path(#driver)
end
end
private
def set_trip
#trip = Trip.find(params[:id])
end
def trip_params
params.require(:trip).permit(:trip_number, :date, :driver_id, :total)
end
end
Mileage Controller
def new
#mileage = Mileage.new
end
def create
#mileage.create(mileage_params)
end
private
def mileage_params
params.require(:mileage).permit(:miles, :rate, :total)
end
end
end
Driver Controller
def index
#drivers = Driver.all
end
def show
end
def new
#driver = Driver.new
end
def edit
end
def create
#driver = Driver.new(driver_params)
respond_to do |format|
if #driver.save
format.html { redirect_to #driver, notice: 'Driver was
successfully created.' }
format.json { render :show, status: :created, location: #driver }
else
format.html { render :new }
format.json { render json: #driver.errors, status:
:unprocessable_entity }
end
end
end
private
def set_driver
#driver = Driver.find(params[:id])
end
def driver_params
params.require(:driver).permit(:first_name, :last_name, :email, :unit)
end
end
If you want to create nested models on the same page. i.e. milages within trip page using accepts_nested_attributes_for, You can use cocoon gem.
https://github.com/nathanvda/cocoon
Drifting Ruby has a video that shows the process in detail that is easy to follow.
https://www.youtube.com/watch?v=56xjUOAAZY8
You can do it manually as well but it will require a little bit more work.
With cocoon you will do have a Driver Controller and Trip controller but you don't need a Milage controller since it is handled with nested_attributes via Trip Controller.
If you want to do it manually, you will need a bit of JavaScript. You can follow Ryan Bates RailsCast on this topic.
railscasts.com/episodes/196-nested-model-form-revised

friendly_id creates new entry on UPDATE

I'm using friendly_id 5.1.0, and when I try to update an entry, for exemple creating a new Article, instead of updating the data of the entry, it creates a new one.
I have slugged the title and when I don't change it when editing an article, it creates a slug with a bunch of numbers/letters :
http://localhost:3000/articles/first-article-2d392b8e-92b8-44b0-ad67-50dd674f7aaa
Here's my article.rb Model :
class Article < ActiveRecord::Base
extend FriendlyId
has_many :comments
friendly_id :title, :use => :slugged
validates :title, presence: true,
length: { minimum: 5}
def should_generate_new_friendly_id?
new_record? || title_changed?
end
when I add :use => [:slugged, :history], when I update an entry and keep the same title, it can't save it because my :slug field is unique :true.
Here's my articles_controller.rb :
class ArticlesController < ApplicationController
def index
#articles = Article.all.order(created_at: :desc)
end
def show
#article = Article.friendly.find(params[:id])
if request.path != article_path(#article)
redirect_to #article, status: :moved_permanently
end
end
def new
#article = Article.new
end
def edit
#article = Article.friendly.find(params[:id])
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def update
#article = Article.friendly.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
def destroy
#article = Article.friendly.find(params[:id])
#article.destroy
redirect_to articles_path
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
Here's my GitHub repository whith my (unfinished) project : https://github.com/TheDoctor314/blog
This issue has nothing to do with FriendlyID.
Your problem is here (a form used on both new and edit):
<%= bootstrap_form_for :article, url: articles_path do |f| %>
It does not attempt to use your #article object to built that form. So your form always issues a POST request to articles_path, which results in create every time. What you should do instead is:
<%= bootstrap_form_for #article do |f| %>
That way form builder will check if that object is persisted? already, and if so, generate a form that issues a PATCH request to that specific article that triggers an update action. It will try to guess the URL by itself. And it will succeeed only if you follow conventions tightly enough.
If #article is not persisted?, it will do what it did: make a POST to articles_path.
Permit id in params
params.require(:article).permit(:id, :title, :text)
Hope that helps!
The Edit form is routing to create action for articles controller instead of update action. You need to change your form path, when editing the files.
If you see the articles index action, you can see new articles are being added, instead of updating

forbidden attribute error rails 4 Carrierwave

Have a issue with a controller file which i have narrowed down to a method
Controller
def create
#gallery = Gallery.new(params[:gallery])
if #gallery.save
flash[:notice] = "Successfully created gallery."
redirect_to #gallery
else
render :action => 'new'
end
end
private
def gallery_params
params.require(:gallery).permit(:name, :gallery, :gamepic)
end
end
the problem is that there is no attr_accessible in the controller or the model
model
class Gallery < ActiveRecord::Base
has_many :gamepics
private
def gallery_params
params.require(:gallery).permit(:name, :gallery, :gamepic)
end
end
Try passing the strong parameters method into Gallery.new instead of params[:gallery].
My understanding of this is that, the hash returned from that method is what should be used anyways. So you'd have:
#gallery = Gallery.new(gallery_params)
If you only need certain params from your :permit call, just make a new strong params method and use that one.

Rails 4 - railscast #154 polymorphic association

Im following ryan bates screen cast on polymoprhic associations
http://railscasts.com/episodes/154-polymorphic-association-revised?view=asciicast
I've done this sucessfully before on a Rails 3 app but now im on Rails 4 and i feel like im having issues with strong parameters..... but i can be wrong
when i go into my console to create a new event for a user it works
a = Event.first
c = a.events.create!(name: "Hello World")
this works and posts on my events index page
howwever when i try to use the actual form on the site it creates the record but the name field is nil and blank...and i dont get any errors
heres my controller (im basically just copying what Ryan Bates does on the site)
class EventsController < ApplicationController
before_filter :load_eventable
def index
#eventable = Admin.find(params[:admin_id])
#events = #eventable.events
end
def new
#event = #eventable.events.new
end
def create
#event = #eventable.events.new(params[:events])
if #event.save
redirect_to [#eventable, :events], notice: "Event created."
else
render :new
end
end
private
def load_eventable
resource, id = request.path.split('/')[1,2]
#eventable = resource.singularize.classify.constantize.find(id)
end
def events
params.require(:events).permit(:name, :address, :city, :state, :zip, :date, :time, :admin_id)
end
end
here my form (very simple and im just using name for now)
= form_for [#eventable, #event] do |f|
.field
= f.text_field :name
= f.submit
Try the below: creating a new event with the event_params method you defined instead of the params hash. I changed the name to make it a little less confusing.
class EventsController < ApplicationController
...
def create
#event = #eventable.events.new(event_params)
if #event.save
redirect_to [#eventable, :events], notice: "Event created."
else
render :new
end
end
private
...
def event_params
params.require(:events).permit(:name, :address, :city, :state, :zip, :date, :time, :admin_id)
end
end

Split hash request into separate strings rails

How would I go about splitting this hash request into two different strings?
I want to split it at #<ActionDispatch, which marks the beginning of the next image selected in the request. How do I accomplish this in ruby?
Request
{"image"=>{"picture"=>[#<ActionDispatch::Http::UploadedFile:0x10c986d88 #tempfile=#<File:/var/folders/bx/6z1z5yks56j40v15n43tjh1c0000gn/T/RackMultipart20130404-53101-3c2whv-0>,
#headers="Content-Disposition: form-data; name=\"image[picture][]\"; filename=\"background-pic.jpg\"\r\nContent-Type: image/jpeg\r\n",
#content_type="image/jpeg",
#original_filename="background-pic.jpg">,
#<ActionDispatch::Http::UploadedFile:0x10c986d60 #tempfile=#<File:/var/folders/bx/6z1z5yks56j40v15n43tjh1c0000gn/T/RackMultipart20130404-53101-bvdysw-0>,
#headers="Content-Disposition: form-data; name=\"image[picture][]\"; filename=\"bible-banner.png\"\r\nContent-Type: image/png\r\n",
#content_type="image/png",
#original_filename="bible-banner.png">],
"album_id"=>"10"},
"authenticity_token"=>"dr8GMCZOQo4dQKgkM4On2uMs8iORQ68vokjW0e4VvLY=",
"commit"=>"Submit",
"utf8"=>"✓",
"album_id"=>"10"}
Controller
class Admin::ImagesController < ApplicationController
respond_to :html, :json
def index
#album = Album.find(params[:album_id])
#images = #album.images.all
end
def new
#album = Album.find(params[:album_id])
#image = #album.images.new
##image.picture.size.times {#image.build}
end
def create
#album = Album.find(params[:album_id])
#image = #album.images.new(params[:image])
if #image.save
flash[:notice] = "Successfully added image!"
redirect_to [:admin, #album, :images]
else
render 'new'
end
end
def show
#album = Album.find(params[:album_id])
#image = #album.images.find(params[:id])
end
def edit
#album = Album.find(params[:album_id])
#image = #album.images.find(params[:id])
end
def update
#album = Album.find(params[:album_id])
#image = #album.images.find(params[:id])
if #image.update_attributes(params[:image])
flash[:notice] = "Successfully updated Image"
redirect_to [:admin, #album, :images]
else
render "edit"
end
end
def destroy
#album = Album.find(params[:album_id])
#image = #album.images.find(params[:id])
#image.destroy
#albumid = #album.id
#id = #image.id
FileUtils.remove_dir("#{Rails.root}/public/uploads/image/picture/#{#albumid}/#{#id}", :force => true)
redirect_to admin_album_images_path(#album)
end
end
Model
class Image < ActiveRecord::Base
attr_accessible :title, :description, :picture, :image_id, :album_id, :albumcover, :image
belongs_to :album
accepts_nested_attributes_for :album
mount_uploader :picture, PictureUploader
end
Form View
<%= form_for([:admin, :album, #image], :html => {:multipart => true}) do |f| %>
<%= f.hidden_field :album_id, :value => #album.id %>
<%= f.file_field :picture, :multiple => true %>
<%= f.submit "Submit" %>
<%end%>
Uploader Carrierwave
class PictureUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
# include CarrierWave::MiniMagick
# Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility:
# include Sprockets::Helpers::RailsHelper
# include Sprockets::Helpers::IsolatedHelper
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.album_id}/#{model.id}"
end
end
As a few commenters said above, what you have is a hash (key/value pair) with the key picture where the value is already an array, which by its nature is split up into discrete objects.
In order to access the array you need to ask for the picture key, then you can access each UploadedFile with Array methods.
So starting with your initial hash:
hash_with_stuff = { "picture" => [#<UploadedFile1>,#<UploadedFile2>]}
#=> { "picture" => [#<UploadedFile1>,#<UploadedFile2>]}
In order to get the array:
array_of_pictures = hash_with_stuff["picture"]
#=> [#<UploadedFile1>,#<UploadedFile2>]
Now that you have the array, you can operate on it as you would any array:
# to get single elements out
array_of_pictures[0] # where the number is the index of the object in the array (starting with 0)
#=> #<UploadedFile1> #this is an UploadedFile object and will respond to its own methods
# to operate on each element with some method
array_of_pictures.each do |picture|
picture.create_thumbnail
end
Does this make sense or were there other questions about working with this?
Lets take a look at this hash h={"strings"=>["stirng_object_1","string_object_2"]} which is almost similar to the hash that you posted except that the objects in the array are strings instead of ActionDispatch::Http::UploadedFile Objects.
So from my example hash that I cited if I have to get first string object I would do
h["string"][0]
Similarly if you would like to access the first ActionDispatch::Http::UploadedFile Objects you can do ( assuming that your hash name is h )
h["picture"][0]
I figured out how to split this hash request into its separate strings.
Image Controller
def new
#album = Album.find(params[:album_id])
#image = #album.images.new
end
def create
params[:image][:picture].each do |image|
#album = Album.find(params[:album_id])
#params = {}
#params['picture'] = image
#image = #album.images.create(#params)
end
if #image.save
if params[:image][:picture].size > 1
flash[:notice] = "Successfully added images!"
else
flash[:notice] = "Successfully added image!"
end
redirect_to [:admin, #album, :images]
else
render "new"
flash[:notice] = "Did not successfully add image :("
end
end

Resources