sorry for my english.
For now i can create Task with one picture attached to it, i want more...
I have Rails on back-end and AngularJS on front-end. I create a directive which helps me send image to server via json.
app.directive 'uploadImage', ->
return{
restrict: 'A'
link:(scope,elem)->
reader = new FileReader()
reader.onload =(e)->
scope.iFile = btoa(e.target.result)
scope.$apply()
elem.on 'change', ->
scope.iFile=''
file = elem[0].files[0]
scope.iFilesize = file.size
scope.iFiletype = file.type
scope.iFilename = file.name
scope.$apply()
reader.readAsBinaryString(file)
}
Create task in AngularJS:
$scope.createTask =->
$scope.task.iFile = $scope.iFile
$scope.task.iname = $scope.iFilename
$scope.task.itype = $scope.iFiletype
baseTasks.post($scope.task).then (data)->
$scope.tasks.unshift($scope.task)
$scope.go('/tasks')
,(error)->
# some code
On the server-side i have a model Task.rb with this settings :
require 'file_size_validator'
class Task < ActiveRecord::Base
belongs_to :user
belongs_to :category
has_many :comments, as: :commentable, dependent: :destroy
validates_presence_of :title
validates_presence_of :text
validates_presence_of :price
mount_uploader :pict, ImageUploader
validates :pict,
:file_size => {
:maximum => 0.5.megabytes.to_i
}
end
and TasksController, action Create :
def create
params[:task][:pict] = parse_image_data(params[:iFile]) if params[:iFile]
@task = Task.new(task_params)
if @task.save
clean_tempfile
render_with_protection @task.to_json, {status: :created, location: @task }
else
render_with_protection @task.errors.to_json, {status: :unprocessable_entity }
end
end
private
def task_params
params.require(:task).permit(:desc, :text, :price, :title, :ed, :category_id, :pict, :user_id)
end
def parse_image_data(image_data)
Rails.logger.info 'decoding now'
decoded_data = Base64.decode64(image_data)
# create 'file' understandable by Carrierwave
@data = StringIO.new(decoded_data)
@tempfile = Tempfile.new('task-image')
@tempfile.binmode
@tempfile.write decoded_data
@tempfile.rewind
ActionDispatch::Http::UploadedFile.new(
:tempfile => @tempfile,
:content_type => params[:itype],
:filename => params[:iname]
)
end
def clean_tempfile
if @tempfile
@tempfile.close
@tempfile.unlink
end
end
Where i decoded image and attach it to model as Carrierwave need.
So please help me with attaching more than one image to my model. Thanks in advance.
You have to loop through each image in your uploadImage directive like this :
reader = new FileReader()
reader.onload = (e) ->
scope.iFile = btoa(e.target.result)
scope.$apply()
elem.on "change", ->
i = 0
while i < elem.length
x = 0
while x < elem[i].files.length
file = elem[i].files[x]
scope.iFile = ""
scope.iFilesize = file.size
scope.iFiletype = file.type
scope.iFilename = file.name
scope.$apply()
reader.readAsBinaryString file
x++
i++
return
And in your html you should have multiple true in your file input.
<input type='file' ng-mpdel='abc' multiple>
Solved. I had to create model Image with polymorphic association.So my models are :
require 'file_size_validator'
class Image < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
mount_uploader :picture, PictureUploader
validates :picture,
:file_size => {
:maximum => 0.5.megabytes.to_i
}
end
class Task < ActiveRecord::Base
belongs_to :user
belongs_to :category
has_many :comments, as: :commentable, dependent: :destroy
has_many :images, as: :imageable, dependent: :destroy
end
Code for upload images in a view:
<input type="file" multiple accept="image/png, image/gif, image/jpeg" upload-image/>
Create directive in angularJS with help @Nitin Verma (thank you!)
app.directive 'uploadImage', ['Restangular',(Restangular)->
baseImages = Restangular.all('images')
return{
restrict: 'A'
link: (scope, elem)->
elem.on 'change', ->
i = 0
im =[]
filD =[]
while i < elem.length
x = 0
while x < elem[i].files.length
reader = new FileReader()
reader.onload = (e)->
im.push(btoa(e.target.result))
scope.$apply()
file = elem[i].files[x]
scope.files = elem[0].files
scope.iFile = ""
filD[x]=[]
filD[x].push(file.type)
filD[x].push(file.name)
scope.$apply()
reader.readAsBinaryString file
x++
i++
scope.arImages = im
scope.fileInf = filD
return
}
]
And my $scope.createTask :
$scope.createTask =->
$scope.task.ed = $scope.edIz.name
$scope.task.category_id = $scope.category_id.id
$scope.task.user_id = $scope.curr.id
baseTasks.post($scope.task).then (data)->
$scope.taskId =data.id
i = 0
while i < $scope.arImages.length
$scope.image ={}
$scope.image.pict = $scope.arImages[i]
$scope.image.iname = $scope.fileInf[i][1]
$scope.image.itype = $scope.fileInf[i][0]
$scope.image.task_id =$scope.taskId
console.log($scope.image.task_id)
imageRes.save( $scope.image )
i++
$scope.tasks.unshift($scope.task)
$scope.go('/tasks')
,(error)->
flash.error = error
I had to use $resource, because double save with Restangular is hangs the app without errors. so :
app.factory('imageRes', ['$resource', ($resource)->
return $resource('/images/:id.json', {id: '@id'}, {
update: {method:'PUT'},
show: {method:'GET'},
delete: {method:'DELETE'}
})])
On the server side in ImagesController, action create:
def create
params[:image][:picture] = parse_image_data(params[:pict]) if params[:pict]
@image = Image.new(image_params)
clean_tempfile
if @image.save
# render_with_protection @task.to_json, {status: :created, location: @task }
render json: @image
else
render_with_protection @image.errors.to_json, {status: :unprocessable_entity }
end
end
Method parse_image_data is the same as in question description.
If anybody knows better way to solve this, please write it !
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.