Config CarrierWave with Mongoid - GridFS - mongodb

I am getting a trouble, trying to use CarrierWave for a file upload Rest API developed in Rails 3, with a MongoDB database.
What I would like to do is storing some files (not only images but every file format) with the MongoDB system GridFS.
I read many documentations that recommend my to use the CarrierWave gem.
But I have an error when I try to configure it.
My development environment :
The Gemfile :
source 'https://rubygems.org'
gem 'rails', '3.2.8'
# MongoDB
gem 'mongoid', :git => 'git://github.com/mongoid/mongoid.git'
gem 'carrierwave', :git => "git://github.com/jnicklas/carrierwave.git"
# gem 'carrierwave-mongoid', :require => 'carrierwave/mongoid'
gem 'mini_magick', :git => 'git://github.com/probablycorey/mini_magick.git'
gem 'bson_ext'
gem 'json'
The application.rb :
require File.expand_path('../boot', __FILE__)
# ActiveRecord will not be use with MongoDB
# require 'rails/all'
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "rails/test_unit/railtie"
require "sprockets/railtie"
require "mongoid/railtie"
require "carrierwave"
# require "carrierwave/mongoid"
I define the database with a mongoid.yml (config/mongoid.yml) file :
development:
sessions:
default:
database: lf_rest_api_development
hosts:
- localhost:27017
options:
consistency: :strong
options:
test:
sessions:
default:
database: lf_rest_api_test
hosts:
- localhost:27017
options:
consistency: :strong
And load it with an initializer (config/initializers/mongoid.rb) :
Mongoid.load!("config/mongoid.yml")
-- I can execute the "rails server" command without problems after the last file, config/initializers/carrierwave.rb :
CarrierWave.configure do |config|
config.grid_fs_database = Mongoid.database.name
config.grid_fs_host = Mongoid.config.master.connection.host
config.storage = :grid_fs
config.grid_fs_access_url = "/files"
end
And then get the following error when I run the "rails server" command :
=> Booting WEBrick
=> Rails 3.2.8 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
Exiting
/{API_path}/config/initializers/zcarrierwave.rb:4:in `block in <top (required)>': undefined method `database' for Mongoid:Module (NoMethodError)
[...]
My file model is defined as following :
require 'carrierwave/orm/mongoid'
class File
include Mongoid::Document
store_in_collection: "files", database: "lf_rest_api_developement", session: "default"
key :filename, type: String
key :content_type, type: String
key :length, type: BigDecimal
key :chunk_size, type: Integer, :default => 256
key :upload_date, type: DateTime
key :md5, type: String
key :metadata, type: Array, :default => []
mount_uploader :file, FileUploader
index({ location: "2d" }, { min: -200, max: 200 })
end
The FileUploader is just an extension of CarrierWave uploader...
class FileUploader < CarrierWave::Uploader::Base
storage :grid_fs
end

Sorry about the slow response. Firstly, the reason for your error is that Mongoid 3 no longer supports Mongoid.database. You can now find these configurations in the Mongoid::Config.sessions[:default] object.
BUT THIS AIN'T GONNA FIX YOUR PROBLEM! Mongoid 3 has no GridFS support at all. From mongoid docs:
No GridFS Support
GridFS is marketed as a core database feature, when in fact it is not. It is simply a pattern for storing chunked file data as documents in a collection, just like any other document. The implementation of this behaviour is handled in the client drivers, not in the core database itself, which can lead to discrepencies in how this is handled across > platforms.
Even if having this behaviour in the client is acceptable, the effects of this on application performance where you are not just storing file data is quite large. Since files are stored as documents, they consume RAM just as any other document in the database would, and can easily cause memory consumption on your server to max out. There are also limitations in chunking the data, such as you do not have the ability to update a file - you must delete the file and replace it with a new one.
Given this, we did not prioritize any work with GridFS at the front, but there is a gem in the pipeline for those who can wait a bit to upgrade. In the meantime you have a few options...
So rather than seek other ways to store uploads in the GridFS at the expense of performance, I would suggest just throwing them in a SQL database. If your using Mongo as your only database, don't be put off by this option. It's not very difficult to get ActiveRecord and Mongoid working together side-by-side. But from my experience, uploading binary objects to any database may not perform well. I would personally use a filesystem for storage, with carrierwave or paperclip taking care of the management. Alternatively, I would suggest checking out some cheap cloud storage options. You can use something like aws-s3, a great service. It also has very well documented compatibility with Carrierwave.
If you are determined to use GridFS, I would check out the mongoid-grid_fs gem or check out some alternative ruby MongoDB drivers on the 10gen website.

This is my first time answering a question so I hope I'm doing this right.
I was struggling with the same issue uploading an image using carrier wave in my rails application with Mongoid 3. I believe I have a solution (at least got it working locally on my laptop.) Here is what I came up with:
Add carrierwave-mongoid gem to your gemfile with the branch mongoid-3.0. This gem uses mongoid-grid_fs:
# Image Uploading
gem "carrierwave-mongoid", :git => "git://github.com/jnicklas/carrierwave-mongoid.git", :branch => "mongoid-3.0"
Make an initializer for carrier wave:
#config/initializers/carrierwave.rb
CarrierWave.configure do |config|
config.storage = :grid_fs
# Storage access url
config.grid_fs_access_url = "/upload/grid"
end
I know I didn't set config.grid_fs_database or config.grid_fs_host. This seems to work locally (on my laptop) I haven't tried it with a remote gridfs database.
Mounting looks normal:
#app/models/user.rb
class User
include Mongoid::Document
mount_uploader :avatar, AvatarUploader
end
Uploader is also standard:
#app/uploaders/avatar_uploader
class AvatarUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
def store_dir
"#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
version :thumb do
process :resize_to_limit => [200, 200]
end
end
Create a controller for GridFS:
#app/controllers/gridfs_controller.rb
class GridfsController < ApplicationController
def serve
gridfs_path = env["PATH_INFO"].gsub("/upload/grid/", "")
begin
gridfs_file = Mongoid::GridFS[gridfs_path]
self.response_body = gridfs_file.data
self.content_type = gridfs_file.content_type
rescue
self.status = :file_not_found
self.content_type = 'text/plain'
self.response_body = ''
end
end
end
and add the route to the routes file:
#config/routes.rb
match "/upload/grid/*path" => "gridfs#serve"
Hope this helps.

Related

Couldn't load the Unicode tables for UTF8Handler in Rails Admin (1.2.0)

I want to upgrade rails 3 to rails 5. There I am using mongodb as database. I am using rails admin 1.2.0. I am using jruby-9.1.7.0. I am rails api only app. My application gems are given below.
gem 'rails', '~> 5.1.4'
gem 'awesome_print', '~> 1.8.0'
gem 'devise', github: 'plataformatec/devise', :branch => 'master', :ref => "463351922fdafb96c50ba2496c7d0adaa3223283"
gem "doorkeeper-mongodb", github: "doorkeeper-gem/doorkeeper-mongodb"
gem 'cancan', github: 'DevAVIJIT7/cancan', :branch => 'master', :ref => "aa3729bd79d92a993c5186f983eccd2fd496c2d3"
gem 'puma','~> 3.11.0'
gem 'mongoid', '6.2.1'
gem 'mongoid-tree', '~> 2.1.0'
gem 'rails_admin', '~> 1.2'
In my routes rails admin mount path and initializer file look like
mount RailsAdmin::Engine => '/admin', :as => 'rails_admin'
RailsAdmin.config do |config|
RAILS_ADMIN_BASE_PATH = 'godview'
config.main_app_name = Proc.new do |controller|
[ "Admin", "#{controller.params[:action].try(:titleize)}" ]
end
config.authenticate_with do
authenticate_or_request_with_http_basic('Login required') do |username, password|
user = User.where(username: username).first
if user && user.valid_password?(password) && user.role_names.include?("Super Admin")
user
else
nil
end
end
end
end
when I run http://localhost:3000/admin on browser I am getting error.
In console I am getting
Started GET "/godview" for 0:0:0:0:0:0:0:1 at 2018-01-15 14:54:12
+0530
Processing by RailsAdmin::MainController#dashboard as HTML
Completed 401 Unauthorized in 263ms
IOError (Couldn't load the Unicode tables for UTF8Handler (undefined method
`call' for nil:NilClass
Did you mean? caller), ActiveSupport::Multibyte is unusable):
I went through the link Rails: Couldn't load the Unicode tables for UTF8Handler But didn't get any response.
*note : I am using /admin as /godview in my app.
Thanks
We are using Docker on CentOS for our rails projects, and we got this error recently, we fixed it by explicitly specifying the C.UTF8 encoding in the docker file as below:
ENV LANG C.UTF-8
Encoding
By default, Ruby inherits the locale of the environment in which it is run. For most users running Ruby on their desktop systems, that means it's likely using some variation of *.UTF-8 (en_US.UTF-8, etc). In Docker, however, the default locale is C, which can have unexpected results. If your application needs to interact with UTF-8, it is recommended that you explicitly adjust the locale of your image/container via -e LANG=C.UTF-8 or ENV LANG C.UTF-8
References:
https://hub.docker.com/_/ruby/
https://oncletom.io/2015/docker-encoding/

Why I get 500 Error while on XAMPP while loading CodeIgniter 3 database library?

I have gone through number of threads on stackoverflow and on other forums to find the answer but could not find relevant answer. People have applied different approaches but none has worked for me thus far.
I am using CI 3 on XAMPP and whenever I load database library in the model, I run into 500 Error.
Here is my CI database config info:
'hostname' => 'localhost',
'username' => 'my_user',
'password' => 'my_pass',
'database' => 'prod_db',
'dbdriver' => 'mysqli',
'dbprefix' => '',
'pconnect' => FALSE,
PHP ini db libraries are as below:
extension=php_bz2.dll
extension=php_curl.dll
extension=php_fileinfo.dll
;extension=php_ftp.dll
extension=php_gd2.dll
extension=php_gettext.dll
;extension=php_gmp.dll
;extension=php_intl.dll
;extension=php_imap.dll
;extension=php_interbase.dll
;extension=php_ldap.dll
extension=php_mbstring.dll
extension=php_exif.dll ; Must be after mbstring as it depends on it
extension=php_mysqli.dll
;extension=php_oci8_12c.dll ; Use with Oracle Database 12c Instant Client
;extension=php_openssl.dll
;extension=php_pdo_firebird.dll
extension=php_pdo_mysql.dll
;extension=php_pdo_oci.dll
;extension=php_pdo_odbc.dll
;extension=php_pdo_pgsql.dll
extension=php_pdo_sqlite.dll
;extension=php_pgsql.dll
;extension=php_shmop.dll
; The MIBS data available in the PHP distribution must be installed.
; See http://www.php.net/manual/en/snmp.installation.php
;extension=php_snmp.dll
My model code is as below:
class loginmodel extends CI_Model {
public function validate_login($username, $password) {
$this->load->database();
$var = 0;
return $var;
}
}
Whenever I remove $this->load->database(); from the model, my code runs and i am able to redirect to a "Login Failed" page. BUT, whenever I load my database library in autoload.php or load it in above model, code fails.
Autoload.php
$autoload['libraries'] = array('database');
Apache error logs showed below errors but I could not figure as why this was happening.
PHP Warning: PHP Startup: Unable to load dynamic library 'C:\\php\\ext\\php_mysqli.dll' - The specified module could not be found.\r\n in Unknown on line 0
PHP Warning: PHP Startup: Unable to load dynamic library 'C:\\php\\ext\\php_pdo_mysql.dll' - The specified module could not be found.\r\n in Unknown on line 0
Please advise.
EDIT:
I verified all config to be OK and as stated in the comments, I added environment variables to windows and verified through PHPInfo that mysqli and mysqlnd were loaded.
Despite getting all the config right, error still persisted and I did a clean install of CI to reproduce library load failure. This time CI returned an error that db access was denied.
I then realized that after migration, database user was not created in the new environment. So once I created the desired user and assigned it required privileges, I was able to run the code just fine.
Therefore, if anyone encounters such issue in future, below steps might help:
First and foremost, verify if your desired user can access the
database.
Modify your .htaccess to use your desired URL schemes only after
verifying that database connection is working
Then verify that absolute path is available in PHP.ini on XAMPP.
Plus, verify that PHP is added in the environment variables. My
Values on Windows 10 are as follows: Variable Name: PHP , Variable
Value: C:\xampp\php\ext
In CI, mysqli is selected as database driver
In PHP.ini mysqli extension is enabled. i.e. php_mysqli.dll
Echo PHPInfo to verify that mysqli and mysqlnd are available in your
installation.
If nothing works, do a clean install of CI on a separate directory and load database library after setting up your database configuration and before setting up .htaccess until you can reproduce the error.
Hope that error will be eliminated!

Using a config block at the top of the file throws error

I'm trying to set a connection to the database (using Sequel) before the model appears. Well it must be that way but am getting an error
undefined method `configure' for main:Object (NoMethodError)
Here is the code, I don't see anything wrong with setting up the constants there so perhaps it is either something related to the configure block or the config.ru.
require 'sinatra/base'
require 'sequel'
require 'slim'
require 'sass'
require 'sinatra/flash'
require './sinatra/auth'
configure :development do
password = ENV["PGPASSWORD"]
DB = Sequel.postgres('development', user: 'postgres', password: password, host: 'localhost')
end
configure :production do
DB = Sequel.connect(ENV['DATABASE_URL'])
end
Here is the rack file. I tried to do the connect statement in there but failed (so far)
require 'sinatra/base'
require './main'
require './song'
require 'sequel'
map('/songs') { run SongController }
map('/') { run Website}
Not understanding why the configure block will not work.
Edit: I'm guessing because the call to the SongController is in config.ru, the connect statements need to be in there as well.
Edit: And further along , since this is a modular app, a config.yml is probably my best option.
You're using sinatra/base. That means you'll have to use a subclass:
require 'sinatra/base'
require 'sequel'
require 'slim'
require 'sass'
require 'sinatra/flash'
require './sinatra/auth'
class MyApp < Sinatra::Base
configure :development do
password = ENV["PGPASSWORD"]
DB = Sequel.postgres('development', user: 'postgres', password: password, host: 'localhost')
end
configure :production do
DB = Sequel.connect(ENV['DATABASE_URL'])
end
run! if app_file == $0
end
NB: You can just use require sinatra and all the magic without using subclasses will be abailable. Or, if you need a modular app, use Sinatra::Application and you will have all the magic included. See sinatra's readme for full coverage on the differences.

uninitialized constant Mongoid::Slug

this is my first development on rails, so Im still learning. I'm having a problem with mongoid_slug. In my local development mongoid_slug works fine, but when I test it on production I'm having this error:
uninitialized constant Mongoid::Slug
This is my full trace: http://pastebin.com/7x0q5VwY
If I try to save the document error appears.
This is my GemFile:
gem 'rails', '4.0.0'
gem 'mongoid', '~> 4.0.0.beta1', github: 'mongoid/mongoid'
gem 'bson_ext'
gem 'cancan'
gem 'ckeditor'
gem 'mongoid_slug', '3.2'
gem 'sass-rails', '~> 4.0.0'
gem 'bootstrap-sass', '~> 3.1.1'
This is my model:
class Noticium
include Mongoid::Document
include Mongoid::Slug
field :titulo, type: String
slug :titulo, history: true
field :contenido, type: String
field :imagen, type: String
field :imagen_url, type: String
field :tipo, type: String
field :fecha_registro, type: DateTime
validates :titulo, uniqueness: true
validates :titulo, :contenido, :imagen_url, :tipo, presence: true
end
This is part of my controller where the error appears:
private
def set_noticium
#noticium = Noticium.find(params[:id])
end
def noticium_params
params.require(:noticium).permit(:titulo, :contenido, :imagen, :tipo,
:fecha_registro)
end
I have read related info but I can't figure out what could be wrong.
My website is hosted on Digital Ocean, I have checked the version of Rails, Ruby and mongodb they are the same that in my local machine.
Could someone help me to figure whats going on? Why on my local development the slug field is working and on production im having errors.
Thanks in advance.
Maybe the MongoID version?
http://rubygems.org/gems/mongoid_slug
Runtime Dependencies
mongoid > 3.0
And you are using Mongoid 4.0
Update: see this issue on Github: https://github.com/digitalplaywright/mongoid-slug/issues/30
My bad. Have to release master, which works without requiring the
path, to RubyGems.

how to solve 'Mysql2::Error: This connection is still waiting for a result' error with mysql2 and activerecord

Not duplicate of this question with the same title
I am using activerecord with mysql2 and I am designing to handle 10 queries to the same activerecord model/class at a time. Please note I am using strict activerecord and not using mysql queries directly.
I get the calls in Sinatra and then use activerecord to get the data from the DB.
I don't wan't the calls to be blocking so therefore I used mysql2 and I do NOT want to use em-synchrony.
But now I get the following "Mysql2::Error: This connection is still waiting for a result, try again once you have the result:" on subsequent simultanous calls.
I am not establishing connection with pool=10
my class
class User < ActiveRecord::Base
and my code to call
user.find(:all, :conditions => ["id=?", userid])
The mysql2 doc says "To use the ActiveRecord driver (with or without rails), all you should need to do is have this gem installed and set the adapter in your database.yml to "mysql2". That was easy right? :)"
And that is exactly what I have done when I moved from mysql to mysql2.
Why am I getting this error.
Here is a fully working example:
require 'rubygems'
gem 'activerecord', '~> 3.1.0'
gem 'sinatra', '~> 1.3.1'
gem 'mysql2', '~> 0.3.11'
require 'active_record'
require 'sinatra/base'
require 'mysql2'
# thin use the eventmachine thread pool
# you should have at least one connection per thread
# or you can expect errors
EM::threadpool_size = 10
# connect to the database
ActiveRecord::Base.establish_connection(
:adapter => "mysql2",
:database => "test",
:username => "root",
:encoding => 'utf8',
# number of connections openened to the database
:pool => 10
)
class App < Sinatra::Base
get '/db' do
ActiveRecord::Base.connection.execute("SELECT SLEEP(1)")
end
end
run App
to run it save the file as "config.ru" and run it with thin in threaded mode:
thin start -e production --threaded
You can use ab to check that everything is working, I used a tool called siege:
siege -c 10 -r 1 http://localhost:3000/db
You should use a ConnectionPool... Somehow you have 2 connections in a race condition.
I dont use Sinatra, I use Rails, but I had the same problem and solved it like that:
# class ActiveRecord::Base
# mattr_accessor :shared_connection
# ##shared_connection = nil
#
# def self.connection
# ##shared_connection || retrieve_connection
# end
# end
#
# ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
class ActiveRecord::Base
mattr_accessor :shared_connection
##shared_connection = nil
def self.connection
##shared_connection || ConnectionPool::Wrapper.new(:size => 1) { retrieve_connection }
end
end
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
You have to use a connection pool. mysql2 allows the queries to be async, but you can still only send one query at a time to MySQL through one connection. If you send multiple queries through one connection you get the waiting for results message.
Use a connection pool and you should be fine.