Uploading files by ng-file-upload and paperclip - ruby-on-rails

I spent a lot of times with ng-file-upload and rails paperclip and stuck((. In standard view with new.html.erb paperclip works perfect. But with ng-file-upload browser returns an error.
Internal Server Error
bad content body
Or if I change upload in my controller:
afisha: {file: file} => to file: {file: file}
Routing Error:
Routing Error
No route matches [POST] "/public"
Here is my controller:
$scope.upload = function (file) {
console.log(file);
Upload.upload({
url: 'http://localhost:3000/public',
method: 'POST',
afisha: {file: file}
}).then(function (resp) {
console.log('Success ' + resp.config.data.file.name + 'uploaded. Response: ' + resp.data);
}, function (resp) {
console.log('Error status: ' + resp.status);
}, function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name);
});
};
View:
<button class="btn" ngf-select="upload($file)">Upload on file select</button>
Rails controller:
class EventsController < ApplicationController
respond_to :json
before_filter :authenticate_user!
def index
respond_with Event.all
end
def show
respond_with Event.find(params[:id])
end
def create
#event = Event.create(event_params)
#guests = guests_params[:guests].map { |guest|
Guest.create(name: guest[:name], surname: guest[:surname], event: #event)
}
respond_with #event
end
def destroy
#event = Event.find(params[:id])
#event.destroy
end
def authenticate_user!
if user_signed_in?
super
else
redirect_to login_path
end
end
private
def event_params
params.require(:event).permit(:name, :description, :date, :afisha)
end
def guests_params
params.permit(guests: [:name, :surname])
end
end
model:
class Event < ActiveRecord::Base
has_attached_file :afisha, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :afisha, content_type: /\Aimage\/.*\z/
has_many :guests
def as_json(options={})
super(options.merge(include: :guests))
.merge(:afisha => afisha.url)
end
end

Related

i have code which implement upload song to database using plupload-jquery and show in datatable for management but song not saved to database

uploaded_song_datatable.rb --which is used for showing list of song in datatable.
class UploadedSongDatatable < AjaxDatatablesRails::Base
include AjaxDatatablesRails::Extensions::Kaminari
def_delegator :#view, :best_in_place
def_delegator :#view, :link_to
def_delegator :#view, :uploaded_song_path
def_delegator :#view, :autocomplete_album_name_albums_path
def_delegator :#view, :autocomplete_artist_name_artists_path
def_delegator :#view, :autocomplete_genre_name_genres_path
def_delegator :#view, :year_list
def_delegator :#view, :content_tag
def_delegator :#view, :image_tag
def sortable_columns
#sortable_columns ||= [
'UploadedSong.title',
'UploadedSong.artist',
'UploadedSong.album',
'UploadedSong.genre'
]
end
def searchable_columns
#searchable_columns ||= [
'UploadedSong.title',
'UploadedSong.artist',
'UploadedSong.album',
'UploadedSong.genre'
]
end
private
def data
records.map do |record|
[
# best_in_place(record, , :as => :checkbox, :collection => ['<input name="mark[]" type="checkbox">'.html_safe, '<input type="checkbox" checked="true">'.html_safe]),
nil,
"<input type='checkbox' class='checkBoxClass' name=\"songids[]\" value='#{record.id}' >",
best_in_place(record, :is_explicit, :as => :checkbox, :collection => ['<input type="checkbox">'.html_safe, '<input type="checkbox" checked="true">'.html_safe] , url: uploaded_song_path(record, field_to_update: 'is_explicit')),
best_in_place(record, :title, :display_with => lambda { |v| v.blank? ? "( No title )" : v }, url: uploaded_song_path(record, field_to_update: 'title')),
best_in_place(record, :artist, :display_with => lambda { |v| v.blank? ? "( No artist )" : v }, url: uploaded_song_path(record, field_to_update: 'artist'), html_attrs: { "data-autocomplete" => autocomplete_artist_name_artists_path, "object_id" => record.id.to_s }),
best_in_place(record, :album, :display_with => lambda { |v| v.blank? ? "( No album )" : v }, url: uploaded_song_path(record, field_to_update: 'album'), html_attrs: { "data-autocomplete" => autocomplete_album_name_albums_path }),
best_in_place(record, :genre, :display_with => lambda { |v| v.blank? ? "( No genre )" : v }, url: uploaded_song_path(record, field_to_update: 'genre'), html_attrs: { "data-autocomplete" => autocomplete_genre_name_genres_path }),
best_in_place(record, :year, :as => :select, :collection => year_list, :display_with => lambda { |v| v.blank? ? "( No year )" : v }, url: uploaded_song_path(record, field_to_update: 'year')),
best_in_place(record, :track, :display_with => lambda { |v| v.blank? ? "( No track )" : v }, url: uploaded_song_path(record, field_to_update: 'track')),
best_in_place(record, :comment, :display_with => lambda { |v| v.blank? ? "( No comment )" : v }, url: uploaded_song_path(record, field_to_update: 'comment')),
if record.cover_id.blank?
link_to("No Cover", "#cover_modal", data: {song_id: record.id, toggle: "modal", multiqueue: 'false'})
else
link_to("#") do
image_tag(record.cover.cover_pic.url, href: "#cover_modal", height: '50', width: '50', data: {song_id: record.id, toggle: "modal", src: record.cover.cover_pic.url, multiqueue: 'false'})
end
end,
link_to(uploaded_song_path(record), method: :delete, data: { confirm: "Are you sure to delete the song ?"}) do
content_tag :span, '', class: "glyphicon glyphicon-trash glyphicon-red"
end
]
end
end
def get_raw_records
UploadedSong.all
end
end
uploaded_song_controller.rb
require 'taglib'
class UploadedSongsController < ApplicationController
before_action :authenticate_user!
authorize_resource
respond_to :json, :html, :js
def index
if params[:from_modal]
sleep(10)
flash[:notice] = "Click 'Refresh', to view recently uploaded songs."
end
#songs = UploadedSong.count
respond_to do |format|
format.html
format.json { render json: UploadedSongDatatable.new(view_context) }
end
end
def new
#song = UploadedSong.new
end
def create
Rails.logger.debug params[:file]
extraction_path = Pathname.new("#{Rails.root}/public")
file_ext = File.extname(params[:file].original_filename)
original_file_name = params[:file].original_filename
tmp_file_base_name = File.basename(params[:file].path)
uploaded_tmp_file = "#{extraction_path}/#{tmp_file_base_name}"
uploaded_file = "#{extraction_path}/#{original_file_name}"
if params[:file].content_type == "application/zip"
Rails.logger.debug "moving #{params[:file].path} to #{extraction_path}"
FileUtils.mv(params[:file].path, extraction_path)
Rails.logger.debug "file moved"
if File.rename(uploaded_tmp_file, uploaded_file)
Resque.enqueue(ZipExtractor, uploaded_file, extraction_path.to_s, true, false)
Rails.logger.debug "Background job started"
head 200
else
File.delete(uploaded_tmp_file) if File.exist?(uploaded_tmp_file)
end
elsif %w(.mp3 .ogg .mp4 .m4a).include?(file_ext)
FileUtils.mv(params[:file].path, extraction_path)
if File.rename(uploaded_tmp_file, uploaded_file)
Rails.logger.info "renaming #{tmp_file_base_name} to #{original_file_name}"
Resque.enqueue(ZipExtractor, false, uploaded_file, false, false)
head 200
else
File.delete(uploaded_tmp_file) if File.exist?(uploaded_tmp_file)
head 200
end
else
File.delete(params[:file].path) if File.exist?(params[:file].path)
head 200
end
end
def edit
#song = UploadedSong.find(params[:id])
end
def update
#song = UploadedSong.find(params[:id])
#song.field_to_update = (params[:field_to_update])
if #song.update_attributes(uploaded_song_params)
Resque.enqueue(ZipExtractor, #song.id, false, false, #song.field_to_update)
end
respond_with_bip #song
end
def destroy
#song = UploadedSong.find(params[:id])
#song.destroy!
unless #song.cover_id.blank?
cover = Cover.find(#song.cover_id)
cover.destroy!
end
if session[:ids] == nil
respond_to do |format|
format.html { redirect_to uploaded_songs_url, notice: 'Song was successfully destroyed.' }
format.json { head :no_content }
end
else
session[:ids].delete(#song.id)
respond_to do |format|
format.html { redirect_to uploaded_songs_url, notice: 'Song was successfully destroyed.' }
format.json { head :no_content }
end
end
end
private
def uploaded_song_params
params.require(:uploaded_song).permit(:title, :artist, :album, :year, :track, :genre, :comment, :song_name, :attachment, :is_explicit)
end
def set_session_for_ids
if session[:ids] == nil
session[:ids] = Array.new
end
end
def update_music_metadata?(song)
TagLib::FileRef.open(song.attachment_url) do |fileref|
unless fileref.null?
tag = fileref.tag # true is for writing.
tag.title = song.title
tag.artist = song.artist
tag.album = song.album
tag.year = song.year.to_i
tag.track = song.track.to_i
tag.genre = song.genre
tag.comment = song.comment
if fileref.save
return true
else
return false
end
end
end
end
def update_song_name?(song)
file_handle = File.open(song.song_path)
dir_location = File.dirname(song.song_path)
file_ext = File.extname(song.song_path)
song_name = song.song_name + file_ext
song_path = dir_location + "/#{song_name}"
attachment = File.rename_file(file_handle, song_path)
if song.update_attributes({attachment: attachment, song_name: song_name, song_path: song_path})
return true
else
return false
end
end
end
uploaded_song.rb
require 'file_size_validator'
class UploadedSong < ActiveRecord::Base
belongs_to :cover
mount_uploader :attachment, AttachmentUploader
skip_callback :commit, :after, :remove_attachment!, if: Proc.new{ |s| s.file_keep == true }
validates :attachment, :file_size => { less_than: 200.megabytes }
attr_accessor :file_keep, :field_to_update
end
zip_extractor.rb
require 'taglib'
require 'zip'
class ZipExtractor
#queue = :songs_queue
def self.perform path_to_zip, destination_path, delete = false, field_to_update
if !path_to_zip.blank? and delete and !destination_path.blank? and !field_to_update
unzip(path_to_zip, destination_path)
Dir.glob("#{destination_path}" + '/*') do |music_file|
base_file_name = File.basename(music_file)
next if base_file_name.casecmp("__macosx") == 0
process_song(music_file)
end
end
if !path_to_zip and !delete and !destination_path.blank? and !field_to_update
process_song(destination_path)
end
if !path_to_zip.blank? and !delete and !destination_path and !field_to_update.blank?
log("processing song details update")
song = UploadedSong.find(path_to_zip)
song_details = nil
TagLib::FileRef.open(song.attachment_url) do |fileref|
unless fileref.null?
tag = fileref.tag
case field_to_update.to_s
when "title"
tag.title = song.title
when "artist"
tag.artist = song.artist
when "album"
tag.album = song.album
when "year"
tag.year = song.year.to_i
when "track"
tag.track = song.track.to_i
when "genre"
tag.genre = song.genre
when "comment"
tag.comment = song.comment
else
log 'No parameters for "field_to_update".'
end
unless fileref.save
TagLib::FileRef.open(song.attachment_url) do |fileref|
unless fileref.null?
tag = fileref.tag
song_details = {
title: tag.title,
artist: tag.artist,
album: tag.album,
year: tag.year,
track: tag.track,
genre: tag.genre,
comment: tag.comment,
is_explicit: false
}
end
end
if song_details[:title].downcase.include? 'explicit'
song_details[:is_explicit] = true
end
song.update_attributes(song_details)
end
end
end
end
end
def self.process_song(destination_path)
if %w(.mp3 .ogg .mp4 .m4a).include? File.extname(destination_path)
if %w(.ogg .mp4 .m4a).include? File.extname(destination_path)
destination_path = convert_video_to_audio(destination_path)
end
if %w(.mp3).include? File.extname(destination_path)
process_mp3(destination_path)
else
delete_file(destination_path)
end
else
delete_file(destination_path)
end
end
def self.process_mp3(destination_path)
song_details = extract_metadata(destination_path)
rename_file = File.dirname(destination_path) + "/1-----" + File.basename(destination_path)
extension = File.extname(destination_path)
cover_file_name = nil
rename = File.rename(destination_path, rename_file)
if rename == 0
transcoded_movie, cover_file_name = transcode_file(rename_file, destination_path)
if transcoded_movie.valid?
delete_file(rename_file)
song_details[:attachment] = File.open(destination_path) if File.exist?(destination_path)
# cover = nil
p song_details[:attachment]
unless cover_file_name.nil?
cover = Cover.new({name: File.basename(cover_file_name), cover_pic: File.open(cover_file_name)}) if File.exist?(cover_file_name)
end
song = UploadedSong.new(song_details)
if !cover.blank?
if cover.save
delete_file(cover_file_name)
song.cover_id = cover.id
if song.save
delete_file(destination_path)
end
end
else
p 9999999999999999999999999999999999999999999999999999
p song.valid?
p song.save
p song.errors.any?
p song.errors.full_messages
p 9999999999999999999999999999999999999999999999999999
if song.save!
delete_file(destination_path)
end
end
else
delete_file(destination_path)
delete_file(rename_file)
end
else
delete_file(destination_path)
end
end
def self.convert_video_to_audio(destination_path)
log "Found video file. Converting video to audio."
movie = FFMPEG::Movie.new(destination_path)
if movie.valid?
file_name_with_no_ext = File.basename(destination_path, "#{File.extname(destination_path)}")
out_file = "#{File.dirname(destination_path)}/#{file_name_with_no_ext}.mp3"
out_movie = movie.transcode(out_file)
if out_movie.valid?
delete_file(destination_path)
destination_path = out_file
end
end
return destination_path
end
def self.extract_metadata(destination_path)
log("extracting metadata from media file")
song_details = nil
TagLib::FileRef.open(destination_path) do |fileref|
unless fileref.null?
tag = fileref.tag
song_details =
{
title: tag.title.blank? ? 'Single' : tag.title,
artist: tag.artist.blank? ? 'Single' : tag.artist,
album: tag.album.blank? ? 'Single' : tag.album,
year: tag.year.blank? ? '' : tag.year,
track: tag.track.blank? ? '' : tag.track,
genre: tag.genre.blank? ? '' : tag.genre,
comment: tag.comment.blank? ? '' : tag.comment,
is_explicit: false
}
if song_details[:title].downcase.include? 'explicit'
song_details[:is_explicit] = true
end
if tag.title.blank?
tag.title = "Single"
fileref.save
elsif tag.artist.blank?
tag.artist = "Single"
fileref.save
elsif tag.album.blank?
tag.album = "Single"
fileref.save
end
end
end
return song_details
end
def self.transcode_file(rename_file, destination_path)
movie = FFMPEG::Movie.new(rename_file)
cover_file_name = nil
transcoded_movie = nil
p movie.valid?
if movie.valid?
log "ffmpeg validates file #{rename_file}"
if movie.video_stream == nil
options = {audio_codec: "libmp3lame", audio_bitrate: 320, audio_sample_rate: 44100, audio_channels: 2}
else
log "removing video stream from file and extracting cover"
cover_file_name = extract_image_from_file(rename_file)
# "-vn" flag is used to remove video_stream from mp3 file
options = {audio_codec: "libmp3lame", audio_bitrate: 320, audio_sample_rate: 44100, audio_channels: 2, custom: "-vn"}
end
transcoded_movie = movie.transcode(destination_path, options)
else
log "Unable to process media file."
delete_file(rename_file)
end
return transcoded_movie, cover_file_name
end
def self.extract_image_from_file(rename_file)
cover_file_name = nil
cover_path = "#{Rails.root}/public/covers/"
TagLib::MPEG::File.open(rename_file) do |fileref|
cover_tag = fileref.id3v2_tag
cover_img = cover_tag.frame_list('APIC').first
unless cover_img.blank?
ext = cover_img.mime_type.rpartition('/')[2]
o = [('a'..'i'), ('A'..'Z')].map { |i| i.to_a }.flatten
rand_string = (1..18).map { o[rand(o.length)] }.join
cover_file_name = "#{cover_path}#{File.basename(rename_file).chomp('.mp3').gsub('1-----','')}-#{rand_string}.#{ext}"
File.open(cover_file_name, "wb") { |f| f.write cover_img.picture }
log "cover extracted from media file."
end
end
return cover_file_name
end
def self.delete_file(filename)
File.delete(filename) if File.exist?(filename)
end
def self.log(message)
Rails.logger.debug "\n*********** #{message} ***************"
end
def self.unzip(path_to_zip, destination_path)
log "unzipping #{path_to_zip} \nto #{destination_path}"
Zip::File.open(path_to_zip) do |zip_file|
# log "zip file is #{zip_file}"
zip_file.each do |f|
f_path=File.join(destination_path, f.name)
FileUtils.mkdir_p(File.dirname(f_path))
a = zip_file.extract(f, f_path) unless File.exist?(f_path)
# log "file extraction complete"
# log a
end
log "after zip file loop"
end
# log "removing original zip file"
FileUtils.rm(path_to_zip)
# log "removed zip file from #{path_to_zip}"
end
end
in above means zip_extractor.rb I checked song.valid? it gives me false in rails 6 and error is cover must exist
and I have checked cover is nil but in rails 4 it gives true and also checked in this version also cover is nil but song saved in database in rails but not in rails 6. anyone have proper reason why it behave like this answer fast otherwise mailto: santu.essence#gmail.com

server responded with a status of 404 (Not Found)

I am trying to redo my react rails app with gresql so that I can deploy it with heroku. So far everything is working fine except the fetch POST request. I am getting a 404 (Not Found) error and binding.pry isn't coming up in my terminal so I can't see from the controller.
I think it might have something to do with how it is sending back json with render :json. Before I was using respond_to do |format| format.json {.
import fetch from 'isomorphic-fetch';
export function saveData(rec) {
debugger
return function(dispatch){
return fetch(`/api/v1/charts`, {
credentials: "include",
method: "POST",
headers: {
'Accept': "application/json",
'Content-Type': "application/json",
},
body: JSON.stringify(rec)
})
.then(res => {
return res.json()
}).then(data => {
debugger
dispatch({type: 'ADD_CHART', payload: data})
})
}
}
module Api::V1
class ChartsController < ApplicationController
def index
#charts = Chart.all
render json: #charts, include: ["people", "weights"]
end
def create
binding.pry
#chart = Chart.create(chart_params)
render json: #chart, include: ["people", "weights"]
end
def destroy
Chart.find(params[:id]).destroy
end
private
def chart_params
params.require(:chart).permit(:id, :date, people_attributes: [:name, weights_attributes: [:pounds, :currentDate] ])
end
end
end
module Api::V1
class PersonsController < ApplicationController
def index
#persons = Person.all
render json: #persons, include: "weights"
end
def create
binding.pry
#person = Person.create(person_params)
render json: #person, include: "weights"
end
private
def person_params
params.require(:person).permit(:id, :name, weights_attributes: [:pounds, :currentDate])
end
end
end
module Api::V1
class WeightsController < ApplicationController
def index
#weights = Weight.all
render json: #weights
end
def create
binding.pry
e = Weight.where(:person_id => params[:person_id], :currentDate => params[:currentDate])
if !e.empty?
e.first.pounds = params[:pounds]
e.first.save!
#weight = e
else
#weight = Weight.create(weight_params)
end
render json: #weight
end
private
def weight_params
params.require(:weight).permit(:id, :pounds, :currentDate, :person_id)
end
end
end
class ApplicationController < ActionController::API
end
If you've declared resource routes for your charts, you need to change this line:
return fetch(`/api/v1/charts`, {
to:
return fetch(/api/v1/chart, {
As is, charts is likely triggering a POST to your index action.
Changing my fetch to the full url and removing credentials: "include" worked
import fetch from 'isomorphic-fetch';
export function saveData(rec) {
debugger
return function(dispatch){
var url = 'http://localhost:3001/api/v1/charts';
return fetch(url, {
method: "POST",
headers: {
'Accept': "application/json",
'Content-Type': "application/json",
},
body: JSON.stringify(rec)
})
.then(res => {
return res.json()
}).then(data => {
debugger
dispatch({type: 'ADD_CHART', payload: data})
})
}
}

Json parseerror & unexpected token

Still trying to fix my ajax to work with the controller.
Now I get this error message:
response SyntaxError: Unexpected token j , xhr[object Object] , STATUS parsererror
config.routes
resources :books do
member do
get '/last_chapter/', to: 'chapters#last_chapter', as: 'last_chapter', defaults: { format: 'json' }
end
resources :chapters
end
chapter controller
def last_chapter
#last_chapter = Chapter.order(created_at: :desc).limit(1)
respond_to do |format|
format.json
end
end
last_chapter.json
json.extract! #last_chapter, :id, :title, :characters, :created_at, :updated_at
script.js
$.ajax({
type: "GET",
url: '/books/103/last_chapter.json',
contentType: "application/json",
success: function(data) {
console.log('JAAAA ENDELIG FUNKER DET');
$("body").html(data);
},
error: function(xhr, status, response) {
console.log('response ' + response + ' , xhr' + xhr + ' , ' + 'STATUS ' + status)}
});
Feel like I have tried everything. Please let me know if you need anymore information! :)
I think your problem lies in the routes. Here is what I would do:
resources :books do
get :last_chapter, on: :member
end
books_controller.rb
def last_chapter
#last_chapter = Book.find(params[:id]).chapters.last
respond_to do |format|
format.json do
render json: { does_it_work: :yes }
end
end
end
I assume the following model:
class Book < ActiveRecord::Base
has_many :chapters
end

Podio Ruby Rails shows "nomethoderror"

I'm having problems with the Podio_rails_sample. I've included my leadsController and leads.rb files. The line that gets hung up is field['config']['settings']['allowed_values'].
Line 25 is the problematic one:
NoMethodError in LeadsController#new
undefined method `[]' for nil:NilClass
Extracted source (around line #25):
23 app = Podio::Application.find(APP_ID)
24 field = app.fields.find { |field| field['external_id'] == 'status' }
25 field['config']['settings']['allowed_values']
26 end
27
28 def self.create_from_params(params)
Rails.root: c:/Sites/podio_rails_sample
app = Podio::Application.find(APP_ID)
field = app.fields.find { |field| field['external_id'] == 'status' }
field['config']['settings']['allowed_values']
end
def self.create_from_params(params)
Rails.root: c:/Sites/podio_rails_sample
-----------------------------------
class LeadsController < ApplicationController
before_filter :load_collections, :only => [:new, :edit]
def index
#leads = Lead.all
end
def new
#lead = Lead.new
end
def create
Lead.create_from_params(params['lead'])
redirect_to leads_path, :notice => 'Lead created'
end
def edit
#lead = Lead.find_basic(params[:id])
end
def update
Lead.update_from_params(params[:id], params['lead'])
redirect_to leads_path, :notice => 'Lead updated'
end
def destroy
Lead.delete(params[:id])
redirect_to leads_path, :notice => 'Lead deleted'
end
#protected
def load_collections
#lead_contacts = Lead.space_contacts
#sales_contacts = Lead.users
#statuses = Lead.statuses
end
end
-------------------------------------
- leads.rb file
class Lead < Podio::Item
APP_ID =12328033
SPACE_ID =3204114
# Find all items in the Leads app
def self.all
collection = self.find_all(APP_ID)
collection[:all]
end
# Find valid lead contacts in the space
def self.space_contacts
Podio::Contact.find_all_for_space(SPACE_ID, :order => 'contact', :limit => 12, :contact_type => 'space,connection', :exclude_self => false) rescue []
end
# Find valid sales contacts in the space
def self.users
Podio::Contact.find_all_for_space(SPACE_ID, :order => 'contact', :limit => 12, :contact_type => 'user', :exclude_self => false) rescue []
end
# Find valid statuses
def self.statuses
app = Podio::Application.find(APP_ID)
field = app.fields.find { |field| field['external_id'] == 'status' }
field['config']['settings']['allowed_values']
end
def self.create_from_params(params)
# raise fields.inspect
self.create(APP_ID, { :fields => fields_from_params(params) })
end
def self.update_from_params(id, params)
self.update(id, { :fields => fields_from_params(params) })
end
#
# Map the field values return by the Podio API to simple getters
#
def organization
field_values_by_external_id('company-or-organisation', :simple => true)
end
def lead_contact
field_values_by_external_id('contacts', :simple => true).try(:[], 'name')
end
def sales_contact
field_values_by_external_id('sales-contact', :simple => true).try(:[], 'name')
end
def potential_revenue_value
field_values_by_external_id('potential-revenue').try(:first).try(:[], 'value').to_i
end
def potential_revenue_currency
field_values_by_external_id('potential-revenue').try(:first).try(:[], 'currency')
end
def probability
field_values_by_external_id('probability-of-sale', :simple => true)
end
def status
field_values_by_external_id('status', :simple => true)
end
def followup_at
field_values_by_external_id('next-follow-up').try(:first).try(:[], 'start').try(:to_datetime)
end
protected
def field_values_by_external_id(external_id, options = {})
if self.fields.present?
field = self.fields.find { |field| field['external_id'] == external_id }
if field
values = field['values']
if options[:simple]
values.first['value']
else
values
end
else
nil
end
else
nil
end
end
def self.fields_from_params(params)
{
'company-or-organisation' => params[:organization],
'contacts' => (params[:lead_contact].present? ? params[:lead_contact].to_i : nil),
'sales-contact' => (params[:sales_contact].present? ? params[:sales_contact].to_i : nil),
'potential-revenue' => { :value => params['potential_revenue_value'], :currency => params['potential_revenue_currency'] },
'probability-of-sale' => params[:probability].to_i,
'status' => params[:status],
'next-follow-up' => DateTime.new(params['followup_at(1i)'].to_i, params['followup_at(2i)'].to_i, params['followup_at(3i)'].to_i).to_s(:db)
}.delete_if { |k, v| v.nil? }
end
end

Uploading multiple attachments with rails, paperclip, and angularjs

I've been stuck on this issue for a couple of days and seem to have run into a wall. I am using rails 4.1, angular 1.2.23, and paperclip 4.1. I sampled from many of the solution for similar problems but none seem to have resolved the issue.
When I set up the paperclip attachments inside of the doc model, I was able to upload a single attachment. However, when I separated the attachments from the doc model and added the images model for multiple attachments, I couldn't get it to work.
Here is the code I am using:
doc.rb
class Doc < ActiveRecord::Base
has_many :image, :dependent => :destroy
accepts_nested_attributes_for :image, :reject_if => lambda { |a| a[:content].blank? }, :allow_destroy => true
end
image.rb
class Image < ActiveRecord::Base
belongs_to :doc
has_attached_file :image, :styles => { :lrg => "700x700>", :med => "350x350>", :sml => "100x100>" }, :whiny => false,
:path => ":rails_root/public/system/:attachment/:id/:style/:filename",
:url => "/system/:attachment/:id/:style/:filename"
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
def image=(files = [])
files.each{|f| (#image ||= []) << image.create(image: f) }
end
end
Here is my controller:
class DocsController < ApplicationController
skip_before_filter :verify_authenticity_token
def index
#docs = if params[:keywords]
Doc.where("title ilike ?", "%#{params[:keywords]}%")
else
[]
end
#items = Doc.all
end
def show
#doc = Doc.find(params[:id])
end
def create
if params[:imageData]
decode_image
#doc = Doc.new(#up)
else
#doc = Doc.new(params.require(:doc).permit(:id, :title, :parent, :info))
end
if #doc.save
render 'show', status: 201
else
render json: #doc.errors, status: :unprocessable_entity
Rails.logger.info #doc.errors
end
end
def update
doc = Doc.find(params[:id])
if params[:imageData]
decode_image
doc.update_attributes(#up)
else
doc.update_attributes(params.require(:doc).permit(:id, :title, :parent, :info))
end
head :no_content
end
def destroy
doc = Doc.find(params[:id])
doc.destroy
head :no_content
end
private
def doc_params
#up = params.require(:doc).permit(:id, :title, :parent, :info, image_attributes: [:_destroy, :id, :image])
end
def decode_image
#up = params.require(:doc).permit(:id, :title, :parent, :info, image_attributes: [:_destroy, :id, :image])
# decode base64 string
Rails.logger.info 'decoding now'
decoded_data = Base64.decode64(params[:imageData]) # json parameter set in directive scope
# create 'file' understandable by Paperclip
#data = StringIO.new(decoded_data)
#data.class_eval do
attr_accessor :content_type, :original_filename
end
# set file properties
#data.content_type = params[:imageContent] # json parameter set in directive scope
#data.original_filename = params[:imagePath] # json parameter set in directive scope
# update hash, I had to set #up to persist the hash so I can pass it for saving
# since set_params returns a new hash everytime it is called (and must be used to explicitly list which params are allowed otherwise it throws an exception)
#up[image_attributes: [:image]] = #data # image is the model attribute that is defined as an attachment using paperclip generator
end
end
Here is my upload directive using angular:
angular.module('fileUpload', []) // using restangular is optional
.directive('uploadImage', function () {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
// listens on change event
elem.on('change', function() {
console.log('entered change function');
for (var i = 0; i < elem.length; i++) {
for (var x = 0; x < elem[i].files.length; x++) {
var file = elem[i].files[x];
// gathers file data (filename and type) to send in json
scope.doc.imageContent = file.type;
scope.doc.imagePath = file.name;
console.log(scope.doc.imagePath);
// converts file to binary string
var reader = new FileReader();
reader.readAsBinaryString(file);
reader.onload = function (e) {
// retrieves the image data from the reader.readAsBinaryString method and stores as data
// calls the uploadImage method, which does a post or put request to server
scope.doc.imageData = btoa(e.target.result);
// updates scope
}
scope.uploadImage(scope.doc.imagePath);
scope.$apply();
}
};
});
},
controller: ['$scope', '$location', '$resource', function($scope, $location, $resource){
$scope.uploadImage = function (path) {
var Doc;
Doc = $resource('/docs/:docId', {
docId: "#id",
format: 'json'
}, {
'save': {
method: 'PUT'
},
'create': {
method: 'POST'
}
});
// if updating doc
console.log($scope.doc);
var onError;
onError = function(_httpResponse) {
return flash.error = "Something went wrong";
};
if ($scope.doc.id) {
$scope.doc.$save((function() {
$scope.docImageLink = baseUrl + $scope.doc.image_url;
}), onError);
} else {
console.log("create");
}
};
}]
};
});
And finally, here is my form field:
<input type="file" id="doc.image" name="doc.image" ng-model='doc.image' upload-image multiple/>
<img ng-src="{{userImageLink}}" ng-click="openFileWindow()" ng-class="{ hidden: !userImageLink}" >
<div class="drop-box" ng-click="openFileWindow()" ng-class=" {hidden: userImageLink}">
Add Image
</div>
When I submit the form with multiple attachments, I receive this error in the rails log:
ActiveRecord::UnknownAttributeError (unknown attribute: {:image_attributes=>[:image]}):
app/controllers/docs_controller.rb:21:in `create'
This is my first major rails app so any help would be significantly appreciated. I can also provide any follow up information that is required.
Thanks!

Resources