Uninitialized constant Blitline Gem - ruby-on-rails

I have an issue using Blitline to process images. I've added the gem to my gemfile restarted terminal etc... but in the rails console I get this error when I try to test it:
Loading development environment (Rails 4.0.1)
2.0.0p353 :001 > blitline_service = Blitline.new
NameError: uninitialized constant Blitline
It's the same error I get when I try to use blitline through a model in my app...
NameError in DrawingsController#create
uninitialized constant Drawing::Blitline
Complete model code
class Drawing < ActiveRecord::Base
scope :published, -> { where(published: true) }
attr_accessible :image, :title, :user_id, :week_id, :key, :published, :safe_for_kids
#=mount_uploader :image, DrawingUploader
belongs_to :week
belongs_to :user
def image_name
File.basename(image.path || image.filename) if image
end
before_save :run_blitline_job
private
def run_blitline_job
filename = File.basename(image, '.*')
# self.title ||= sanitize_filename(filename).titleize # set default name based on filename
filename_with_ext = File.basename(image)
key = "uploads/thumbnails/#{SecureRandom.hex}/#{filename_with_ext}"
bucket = ENV["S3_BUCKET"]
images = blitline_job(image, bucket, key)
self.image = images['results'][0]['images'][0]['s3_url'] # extracts s3_url from blitline's ruby hashes
end
def blitline_job(original_image, bucket, key)
blitline_service = Blitline.new
blitline_service.add_job_via_hash({ # New add job method in Blitline gem 2.0.1. Messy.
"application_id" => ENV['BLITLINE_APPLICATION_ID'],
"src" => original_image,
"functions" => [{
"name" => "watermark", # watermark the image
"params" => { "text" => "oh hai" },
"functions" => [{
"name" => "resize_to_fill", # resize after watermark
"params" => { "width" => 200, "height" => 200 },
"save" => {
"image_identifier" => "MY_CLIENT_ID", # Not sure what this is for
"s3_destination" => { "key" => key, "bucket" => bucket } # push to your S3 bucket
}
}]
}]
})
return blitline_service.post_jobs
end
end
Any help appreciated...

Related

Rails: Cannot set option by using method

For example here is my paperclip configuration. Here is my model file:
class File < ApplicationRecord
belongs_to :attachable, polymorphic: true, optional: true
has_attached_file(:attach_file, local_option)
end
In this model file, I have defined two option named local_option and s3_option.
def local_option
{
:storage => :filesystem,
:path => 'public/:class/:id/:basename.:extension'
}
end
def s3_option
{
:storage => :s3,
:s3_headers => lambda { |attachment| {'Content-Type' => attachment.attach_file_content_type} }
}
end
When I run, I meet this error:
method_missing': undefined local variable or method `local_option' for
Class:0x007fc9be09dac8> (NameError)
I don't know why ruby/rails doesn't see local_option method. Please tell me how.
Thanks
It should be class instance method, not instance method.
def self.local_option
{
storage: :filesystem,
path: 'public/:class/:id/:basename.:extension'
}
end
And voila - error is gone.
Advice: since it is non-changing data, I'd put it into a constant:
LOCAL_FILE_OPTIONS = {
storage: :filesystem,
path: 'public/:class/:id/:basename.:extension'
}.freeze
Now
has_attached_file(:attach_file, LOCAL_FILE_OPTIONS)

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!

Paperclip override validates_attachment in subclass

I am trying to override validates_attachment in Subclass but I notice it only works well with Superclass validation; I wonder why my validates_attachment in subclass doesn't work. Has anybody faced this problem? and how have you solved this problem? Here is an example code:
class Superclass
validates_attachment :logo, :image_ratio => { :ratio => {"1:1" => "28", "4:1" => "50", "5:1" => "40"} }
end
class Subclass < Superclass
validates_attachment :logo, :image_ratio => { :ratio => {"1:1" => "40", "2:1" => "60"} }
end
I suggest that you should put both the class's fields in different tables. It could be possible that you are getting problems because of that.
However if you really want to have only one table for both the classes then I believe that you could use something like this:
validates_attachment :logo, :image_ratio => { :ratio => {"1:1" => "40", "2:1" => "60"} }, :unless => Proc.new {|attach| attach.type == "SubClass"}
I assumed that you have a attach_type column but depending on how you are determining whether the attachment type is a SubClass, it is left upto you to change it.
You could also try to remove your validates_attachment from the Subclass and instead try with_options in your model, like the following:
with_options :unless => :attach_type == "SubClass" do |attach|
attach.validates_attachment :logo, :image_ratio => { :ratio => {"1:1" => "40", "2:1" => "60"}}
end
This works for me... rails 4
validates :photo, :presence => true,
:attachment_content_type => { :content_type => "image/jpg" },
:attachment_size => { :in => 0..10.kilobytes }
Incase anyone else runs into an issue where they need instance access before they can validate I used the following:
class AttachmentDynamicContentTypeValidator < Paperclip::Validators::AttachmentContentTypeValidator
def validate_each(record, attribute, value)
#record = record
super
end
def allowed_types
#record.my_valid_types_array || ["text/plain"]
end
def check_validity!; end
end
And in the actual asset instance I added the following:
class Asset < ActiveRecord::Base
validates :asset, attachment_dynamic_content_type: :asset_content_type
end
Hope that helps someone.

Rails seeds.rb undefined method for custom method

I read a few other posts on this subject and am still confused. In my seeds.rb I call delete and create on the model without any issues... when I get to the custom methods I created I get an undefined method error. The create and delete_all work fine when I comment out the name_gen and ssn_gen rows.
Also, this is Rails 3.1.1 on Ruby 1.8.7
Update: should have also mentioned I get the same issue if I change the create to new and move the name_gen sections to something like #sample_data_set.officialFirstName = SampleDataSet.name_gen
Error: undefined method `name_gen' for #
Command for rake: bundle exec rake db:seed RAILS_ENV=development --trace
seeds.rb
SampleDataSet.delete_all
#sample_data_set = SampleDataSet.new (
:campusNum => "96",
:dateOfBirth => "1981-10-09",
:gender => "M",
:officialMiddleInitial => "L",
:addressLine1 => "PO BOX 9",
:addressLine2 => "",
:city => "WOODLAND",
:state => "GA",
:zipCode => "31836",
:homeAreaCode => "706",
:homePhoneNumber => "6742435",
:homePhoneCountryCode => "US",
:workAreaCode => "706",
:workPhoneNumber => "6742435",
:workPhoneCountryCode => "US",
:usCitizen => true,
:financialAid => true,
:previousDegree => "ADN",
:region => "MAIN",
:program => "AAPSY",
:version => "012",
:team => "TEAM 3236A",
:enrollmentUserId => "SSGROTH",
:revCampusOid => "1627",
:executingUserId => "QROBINSO",
:totalDeclaredExtCredits => "1",
#generating some default values for the gen fields... except IRN
:officialFirstName => SampleDataSet.name_gen,
:officialLastName => SampleDataSet.name_gen,
:enrollAgreeSignDate => Date.today.strftime('%Y-%m-%d'),
:scheduledStartDate => Date.tomorrow.strftime('%Y-%m-%d'),
:ssn => SampleDataSet.ssn_gen.to_s
)
#sample_data_set.emailAddresses = officialFirstName + "." + officialLastName + "#aaaa.phoenix.edu"
,
SampleDataSet model
class SampleDataSet < ActiveRecord::Base
#Random info generation
def name_gen(*prepend)
#Random character generation piece I found on Stackoverflow with 102 upvotes
character_map = [('a'..'z'),('A'..'Z')].map{|i| i.to_a}.flatten
name = (0..8).map{ character_map[rand(character_map.length)] }.join
if prepend.nil?
return name
else
return prepend.to_s + "_" + name
end
end
def ssn_gen
#broke this out as its own method in case someone wants some logic later on
ssn = Random.rand(1000000000) + 99999999
return ssn
end
end
In order to call some method directly on class like that:
SampleDataSet.name_gen
instead of calling it on an instance of that class (as regular methods are called) like that:
a = SampleDataSet.new
a.name_gen
you should define that method as a class method.
You can do it using self.name_gen instead of name_gen in method definition like that:
class SampleDataSet < ActiveRecord::Base
# Random info generation
def self.name_gen(*prepend)
# Random character generation piece I found on Stackoverflow with 102 upvotes
character_map = [('a'..'z'), ('A'..'Z')].map { |i| i.to_a }.flatten
name = (0..8).map { character_map[rand(character_map.length)] }.join
if prepend.nil?
return name
else
return prepend + "_" + name
end
end
def self.ssn_gen
# broke this out as its own method in case someone wants some logic later on
ssn = Random.rand(1000000000) + 99999999
return ssn
end
end

Ruby on Rails: I'm trying to recursively generate a hash, but I get {...} where there is supposed to be another depth of data

This is what I've been getting:
{:user=>{:employees=>{...}, :login=>"dernalia", :id=>1, :role=>2}}
What is generating the hash:
def management_tree(args = {})
args = {:users => [], :result => {}}.merge(args) #defaults
result = args[:result]
if not args[:users].include? self.login #prevent duplicates
result.merge!({:user => {:id => self.id,
:login => self.login,
:role => self.role,
:employees => employee_tree(args[:users] + [self.login], args[:result])
}
})
end
logger.info result.inspect
return result
end
def employee_tree(users, result)
if self.employees.length > 0
self.employees.each {|emp| (emp.management_tree({:users => users, :result => result})) }
end
return result
end
Now... it's supposed to return something like this:
{:user=>{:login=>"me", :id=>1, :role=>2,
:employees=>{
:user => {:login => "2", ...},
:user => {:login => "3",
:employees => {...}
}
}}
Some console output:
% bundle exec script/console
Loading development environment (Rails 2.3.8)
>> require "awesome_print"
=> []
>> ap User.find(1).management_tree[:employees]
nil
=> nil
>> ap User.find(1).management_tree
{
:user => {
:employees => {...},
:role => 2,
:login => "me",
:id => 1
}
}
=> {:user=>{:employees=>{...}, :role=>2, :login=>"me", :id=>1}}
>>
now... it says that employees is nil... but it shouldn't be... it should have 3 hashes ... =\
but also, what does {...} mean? it seams terribly ambiguous
Ruby is clever about recursive structures and will use "..." instead of looping indefinitely.
For example:
a = [1, 2]
a << a # a is now recursive, since it contains itself
a.to_s # => [1, 2, [...]]
a[2][2][2][2][2][2][2] == a # => true
In your case, the {...} refers to any of the hashes already in the process of being outputed.
Maybe what you meant to do was to insert a copy of a hash? In the simple array example:
a = [1, 2]
a << a.dup # a is not recursive
a.to_s # => [1, 2, [1, 2]]

Resources