Download image by using Grape and Carrierwave - ruby-on-rails

I in my app/api/myapp/api.rb file I'm writing simple registration method:
params do
requires :email, type: String, regexp: /.+#.+/, allow_blank: false
requires :password, type: String, allow_blank: false
requires :name, type: String, allow_blank: false
requires :surname, type: String, allow_blank: false
requires :person, type: Integer, allow_blank: false
end
post :register do
User.create!(email: params[:email],
password: params[:password],
name: params[:name],
surname: params[:surname],
remote_avatar_url: Faker::Avatar.image)
end
As you can see, I'm using carrierwave gem to keep images of my model User. Now I'm just assigning random image from Faker gem.
How to receive image, that is sent from client and assign it to my new Model?

Just use the Rack::Multipart::UploadedFile as the example below.
desc 'Upload Image.'
params do
requires :file, :type => Rack::Multipart::UploadedFile
requires :id, :type => Integer
end
post ':id/avatar' do
File.open(params[:file].tempfile, 'r') do |f|
# Do whatever you need with this file.
# Here, you can store it in the server filesystem or in your database.
end
end

Related

How can allow_nil let an empty string pass the validation

I am reading Michael Hartl's Ruby On Rails Tutorial (3rd). In chapter 9, there's an example showing us how to update the user info. I got confused by the allow_nil attached here. I simplified the code as below:
class User < ActiveRecord::Base
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
end
myuser=User.new(name: "Foo_bar",email: "test#example.com", password: "123456", password_confirmation: "123456")
myuser.save
myuser=User.find(myuser.id)
myuser.update_attributes(name: "Bar_Foo",email: "test#example.com", password: "", password_confirmation: "") # It will succeed! But WHY?
I understand the allow_nil: true skips the validation when the value being validated is nil. Nevertheless obviously, password: "" is not a nil value. How can allow_nil: true allows an empty string?
This behaviour is due to has_secure_password magic. In short, it check whether given password is blank or not and does not assign anything to #password if it is. Hence:
user = User.new
user.password = '' # This is not an assignment, but invocation of `password=` method.
user.password #=> nil
You can see the source code behind password= method here: https://github.com/rails/rails/blob/869a90512f36b04914d73cbf58317d953caea7c5/activemodel/lib/active_model/secure_password.rb#L122
Also note, that has_secure_password already defines default password validation, so if you want to create your own, you need to call it with has_secure_password validation: false
You can try this in irb:
user = User.new
user.password = '123'
user.password_confirmation = '123'
user.password_digest.nil? => false
user = User.new
user.password = ''
user.password_confirmation = ''
user.password_digest.nil? => true

Carrierwave mongoid upload. Getting an undefined method `empty?' for #<ActionDispatch::Http::UploadedFile:0x00000109968c50>

I'm trying to upload an image file to my rails server, but I keep hitting a wall.
This is my form themed_controller/new ,
= form_for(#campaign, validate: true, :html => {:multipart => true}) do
.form-group
%label.col-sm-3.control-label
Campaign Name
.col-sm-6
%input#title.form-input{ name: "#campaign[campaign_title]", placeholder: "Campaign Title", required: "", type: "text", value: ""}/
.form-group
%label.col-sm-3.control-label
Campaign Description
.col-sm-6
%textarea.form-input{ name: "#campaign[campaign_description]", placeholder: "Campaign Description", required: "", value: ""}
.form-group
%label.col-sm-3.control-label
Pick stories
.col-sm-6
%select#themed_campaign_live_story_ids{name: "#campaign[live_story_ids][]", :multiple => true, :required=> true, value: []}
-# = f.select 'live_story_ids[]', [], :multiple => true
#date-range
.form-group#valid-from
%label.col-sm-3.control-label
Campaign runs from
.col-sm-6
%input.form-input#themed_campaign_valid_from{ name: "#campaign[valid_from]",:class => 'jquery-ui-date valid-from', :data => {:provide =>"datepicker", :behaviour => "datepicker"}, required: "", type: "text", value: ""}/
.form-group#valid-till
%label.col-sm-3.control-label
Campaign runs till
.col-sm-6
%input.form-input#themed_campaign_valid_till{ name: "#campaign[valid_till]",:class => 'jquery-ui-date valid-till', :data => {:provide =>"datepicker", :behaviour => "datepicker"}, required: "", type: "text", value: ""}/
.form-group#valid-till
%label.col-sm-3.control-label
Upload cover (1280x350)
.col-sm-6
-#upload-image.btn.btn-medium.btn-green{ :data => {:url => "/campaign/upload"} }
#upload-image
%input#image_media{name: "#campaign[cover]", type: "file"}/
.form-group
.col-sm-offset-3.col-sm-6
%button.form-button.btn-large.btn-green.btn#campaign-submit{type: "submit"}
Set up Campaign
And this is my create method
def create
campaign = params[:#campaign]
campaign['added_by_email'] = current_user.email
#campaign = ThemedCampaign.create(campaign)
if #campaign.save
img_attr = params[:#campaign]['cover']
image = Campaign.new img_attr
#campaign.cover = image
Resque.enqueue(ImageQueue,image.id)
#render :json => image.to_jq_upload.to_json
end
redirect_to '/admin/themecampaign'
end
I have created a seperate uploader for this,
# encoding: utf-8
class CampaignUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
before :cache, :save_original_filename
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_white_list
%w(jpg jpeg png)
end
# 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/campaigns/#{model.id}/"
end
end
And this is my campaign modal, which hold the image
class Campaign
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Paranoia
include Rails.application.routes.url_helpers
mount_uploader :cover, CampaignUploader
end
Now when I upload the form I keep getting an undefined methodempty?' for #
> NoMethodError - undefined method `empty?' for
> #<ActionDispatch::Http::UploadedFile:0x00000109968c50>: () Users/skmvasu/.rvm/gems/ruby-2.0.0-p451/bundler/gems/mongoid-bc72426681d5/lib/mongoid/attributes/processing.rb:21:in
> `process_attributes' ()
> Users/skmvasu/.rvm/gems/ruby-2.0.0-p451/bundler/gems/mongoid-bc72426681d5/lib/mongoid/document.rb:111:in `block in initialize' ()
> Users/skmvasu/.rvm/gems/ruby-2.0.0-p451/bundler/gems/mongoid-bc72426681d5/lib/mongoid/threaded/lifecycle.rb:84:in
> `_building' ()
> Users/skmvasu/.rvm/gems/ruby-2.0.0-p451/bundler/gems/mongoid-bc72426681d5/lib/mongoid/document.rb:105:in `initialize' actionpack (4.0.2)
> lib/action_dispatch/routing/url_for.rb:104:in `initialize'
> app/controllers/themed_campaign_controller.rb:57:in `new'
> app/controllers/themed_campaign_controller.rb:57:in `create'
Essentially, this blows up while trying to call Campaign.new with the image attributes. I thought the image field was nil but when I inspected the img_attr from the server, I noticed the uploaded file was present and the temp field was corretly pointing to a local copy.
When I dug deeper, I noticed the the cover filed in my themed_controller was invalid.
MOPED: 127.0.0.1:27017 INSERT database=mangoweb_development collection=themed_campaigns
documents=[{"_id"=>BSON::ObjectId('53ba605c5661731da8060000'),
"campaign_title"=>"Test campaign", "campaign_description"=>"Test
campaign desciption", "live_story_ids"=>["53a9b3e5566173146e030000",
"5343eafc5661731195030000", "5343eacc566173117f030000",
"5343eadf5661731189030000"], "valid_from"=>2014-07-07 00:00:00 UTC,
"valid_till"=>2014-07-22 00:00:00 UTC,
"cover"=>"#",
"added_by_email"=>"xxxxxxxxx",
"campaign_sane_title"=>"Test-campaign", "updated_at"=>2014-07-07
08:54:52 UTC, "created_at"=>2014-07-07 08:54:52 UTC}] flags=[]
COMMAND database=mangoweb_development command={:getlasterror=>1, :w=>1}
runtime: 11.9600ms
#
What am I doing wrong here?Why is the value of cover is a String version of the uploaded Object reference, instead of the file values, and why the Image not getting created?
I've been over this issue for the last 2 days, and have looked at various references. I know, I must be doing something very silly, but I'm not able to get it.
Please help me with this issue. Thanks in advance.
You can use form instance object to easily handle this
Change
form_for(#campaign, validate: true, :html => {:multipart => true}) do
to
form_for(#campaign, validate: true, :html => {:multipart => true}) do |f|
and use f while referencing the form fields
%textarea.form-input{ name: "#campaign[campaign_description]", placeholder: "Campaign Description", required: "", value: ""}
should be changed to
f.text_area :campaign_description, placeholder: "Campaign Description", required: "", value: ""
and for the file field
f.file_field :cover
Let me know if that works

No validation errors on sign in, present on sign up with Devise/Rails

Using Devise with Rails, but validating myself in the model to provide custom error messages:
validates :email,
:uniqueness => {:message => :unique_email},
:presence => {:message => :email_missing}
YML:
unique_email: "Email address needs to be unique"
email_missing: "Email address can't be blank"
View:
=#user.errors.messages.inspect
yields nothing, an empty object! Yet this all works fine on sign up...
Any ideas?
EDIT:
Ok, it's putting the login errors in like so:
- flash.each do |name, msg|
.standalone_form--message= msg
So how can I customise these messages (ie. from a yml file)? Like I've done with the #user.errors.messages?
You should put your messages using locales as Rails guides recommends:
# config/locales/en.yml
en:
activerecord:
attributes:
user:
email: "Email address"
errors:
models:
user:
attributes:
email:
blank: "can't be blank"
unique: "should be unique"
Note: Do not use the following, it's only to show the YAML issue
That said, about your error, this should work:
validates :email,
:uniqueness => {:message => "Email address should be unique"}
The problem is that you should load the YAML file properly:
Create a file named config/error_messages.yaml:
unique_email: "Email address needs to be unique"
email_missing: "Email address can't be blank"
Add a Ruby file config/initializers/load_error_messages.rb:
ERROR_MESSAGES = YAML.load_file(Rails.root.join("config", "initializers", "config.yml"))
Then use it on the validation like this:
validates :email,
:uniqueness => {:message => ERROR_MESSAGES['unique_email']}
( Source: RailsCast #85)

Why Rails data loaded from Fixtures are broken?

I got two fixture files for Locales and Translations.
Locales are loaded fine, but Translations are broken:
Fixture
translation_05064:
id: 5064
key: control.base_search_users.panel.title
value: Поиск пользователей
interpolations:
locale: ru
locale_id: 16
is_proc: false
Becomes the record:
#<Translation id: 5064,
key: "control.base_search_users.panel.title",
value: "Поиск пользователей",
interpolations: nil,
locale: nil,
locale_id: 1019186233,
is_proc: false>
For some reason locale instead of 'ru' becomes nil, while locale_ib instead of 16 becomes 1019186233 for every fixture in a file.
I load fixtures such way:
require 'active_record/fixtures'
ActiveRecord::Fixtures.reset_cache
fixtures_folder = File.join(Rails.root, 'test', 'fixtures')
fixtures = Dir[File.join(fixtures_folder, '*.yml')].map {|f| File.basename(f, '.yml') }
ActiveRecord::Fixtures.create_fixtures(fixtures_folder, fixtures)
Translation model
class Translation < ActiveRecord::Base
validates :key, :uniqueness => {:scope => :locale_id}
validates :key, :locale, :locale_id, :value, :presence => true
belongs_to :locale
attr_accessible :key, :value, :locale_id, :locale
end
The migration
class CreateTranslations < ActiveRecord::Migration
def change
create_table :translations do |t|
t.string :key
t.text :value
t.text :interpolations
t.string :locale
t.integer :locale_id
t.boolean :is_proc, :default => false
end
add_index :translations, [:key, :locale]
end
end
I see in a test.log that inserts to DB contain broken data. When I load the fixture file in rails concole with YAML.load_file 'test/fixtures/translations.yml' I get correct Hash data.
Why that happens? How to fix that?
Rails-2.3.8, PostgreSql-8.4
UPDATE:
Tried named fixtures. In locales.yml:
locale_00016:
id: 16
code: ru
name: Русский
and in translations.yml all locale key values set to locale_00016
translation_05064:
id: 5064
key: control.base_search_users.panel.title
value: Поиск пользователей
locale: locale_00016
is_proc: false
YES, that works!
Translation id referred to existing and correct Locale record, but locale was still nil, to fix it I ran Locale.find_by_code('ru').translations.update_all(:locale => 'ru')
If locale_id is set, it seems ok; locale will be filled by Rails when you need it (the first time you will request it). 1019186233 is the id generated by rais when the fixtures are created.
Most of the time, you do not need to specify ids in fixtures, rails generate them for you, so fixtures like below should be fine (you should not define both localeand locale_id in the Translation fixture):
locales.yml:
ru:
what_ever_attr: value
...
translations.yml:
ru_title_translation:
key: control.base_search_users.panel.title
value: Поиск пользователей
interpolations:
locale: ru
is_proc: false

Rails3/Mongoid Validations Not Running

In my application, it seems that no ActiveModel validations are running, at all. That is, they always return true (valid) no matter how invalid the data actually is.
class QueueItem
include Mongoid::Document
include Mongoid::Timestamps
belongs_to :user
field :appointment_time, type: DateTime, allow_nil: true
field :notes, type: String, allow_nil: true
# field :position, type: Integer, default: 0
validates :user, presence: true, allow_blank: false, allow_nil: false
validates_length_of :notes, :minimum => 2, allow_blank: false
end
Then, when you try to save or validate a record with bad data, this is what you get:
ruby-1.9.2-p290 :028 > QueueItem.validators
=> [#<ActiveModel::Validations::PresenceValidator:0x007f8303adb190 #attributes=[:user], #options={:allow_blank=>false, :allow_nil=>false}>, #<ActiveModel::Validations::LengthValidator:0x007f8303ee5a60 #attributes=[:notes], #options={:minimum=>2, :allow_blank=>false}>]
ruby-1.9.2-p290 :029 > qi = QueueItem.new
=> #<QueueItem _id: 4edf5a0535be359a79000004, _type: nil, created_at: nil, updated_at: nil, user_id: nil, appointment_time: nil, notes: nil, called: false, visited: false, rejected: false>
ruby-1.9.2-p290 :030 > qi.notes = "x"
=> "x"
ruby-1.9.2-p290 :031 > qi.valid?
=> true
It seems that the validations are in fact being registered in the model, as shown by QueueItem.validations. Why, then, do they always return true? This is happening not just in this model, but in all models in my application.
UPDATE
I added a custom validator, and that is successfully firing.
validate :test_validation
def test_validation
logger.info ":test_validation has fired"
self.errors[:base] << "Something is royally screwed!"
end
Now, when I call model.valid?, it returns false, and the logger outputs that message. The custom validator is in fact adding errors to the object, and returning false. Still not clear why the standard ActiveModel ones are not being executed. Is there any way to trace these?
So, turns out that there was a corrupted string in the locals/en.yml file under the errors: section.

Resources