How to use Kaminari pagination gem with Sinatra and Mongoid? - ruby

Presumably, not a whole lot of configuration is required - docs. The gem doesn't seem to work. Relevant code:
Gemfile:
source 'https://rubygems.org'
ruby '2.2.4'
gem 'sinatra'
gem 'thin'
gem 'slim'
gem 'json'
gem 'mongoid'
gem 'kaminari'
web.rb:
require 'sinatra'
require 'json'
require 'mongoid'
require 'kaminari'
# Mongoid class
class Affiliate
include Mongoid::Document
field :name, type: String
end
# MongoDB connection info and whatnot
Mongoid.load!('mongoid.yml', :development)
get '/kaminari' do
puts Affiliate.page(1).count
end
Error:
NoMethodError - undefined method `page' for Affiliate:Class

The error message states you can't page a class. Also, calling count on paginated data set isn't a correct use. Instead, first add some selection criteria to the class and then try to page the results. With respect to Mongoid, an example would be:
#paginated_users = User.where(:age.gte => 10).page(10)
By default, kaminari returns 25 items per page, you can change that by appending a per(desired number of items per page) method like so,
#paginated_users = User.where(:age.gte => 10).page(10).per(5)
Lastly, make sure you add a <%= paginate #paginated_users %> (the same variable name declared in your web.rb that contains the dataset to be paginated in the view) in your corresponding view file.

The following worked for me:
require 'mongoid'
require 'kaminari/sinatra'
require 'kaminari/mongoid'
get '/rest/1.0/post' do
# matches "GET /rest/1.0/post?page=1"
page_id = params[:page].to_i
redirect '/rest/1.0/post?page=1' if page_id == 0
page = Post.page(page_id)
json(size: Post.count,
total_pages: page.total_pages,
per_page: page.limit_value,
prev_page: page.prev_page,
current_page: page_id,
next_page: page.next_page,
data: page)
end
And in the Gemfile:
gem 'mongoid'
gem 'kaminari-mongoid'
gem 'kaminari-sinatra'

Related

Rails 4, Strong Parameters, Unpermitted parameters on fields belonging to associated model

This is my first try at using models with associations with Rails 4 and for some reason I'm not able to get at the parameters POST'ed in due to a "Unpermitted parameters" error. I have tried to permit the associated fields several different ways with no success.
Basically, I have an Adoption Request with an associated Person.
class AdoptionRequest < ActiveRecord::Base
has_one :person
accepts_nested_attributes_for :person
end
and
class Person < ActiveRecord::Base
belongs_to :adoption_request
end
Here are the relevant sections from adoption_requests_controller.rb:
def create
#adoption_request = AdoptionRequest.new(adoption_request_params)
respond_to do |format|
if #adoption_request.save
format.html { redirect_to #adoption_request, notice: 'Adoption request was successfully created.' }
format.json { render action: 'show', status: :created, location: #adoption_request }
else
format.html { render action: 'new' }
format.json { render json: #adoption_request.errors, status: :unprocessable_entity }
end
end
end
private
def adoption_request_params
params.require(:adoption_request).permit(person_attributes: [:first_name, :last_name])
end
The form in the view is generated using rails-bootstrap-forms:
= bootstrap_form_for #adoption_request do |f|
= f.fields_for #adoption_request.person do |owner_fields|
= owner_fields.text_field :first_name
= owner_fields.text_field :last_name
= f.submit
Here is an example of the HTML generated by this for the first name field:
<input class="form-control" id="adoption_request_person_first_name" name="adoption_request[person][first_name]" type="text">
Now when I submit the following POST payload:
{"utf8"=>"✓", "authenticity_token"=>"kE1Q222VzXRsuLnhiO0X3mijW1TGTWSAOVgVDz/rxsE=", "adoption_request"=>{"person"=>{"first_name"=>"John", "last_name"=>"Smith"}}, "commit"=>"Create Adoption request"}
The adoption request is created, but the associated person is not. This is appears to be happening because strong parameters is not allowing the person parameters to come through. Case in point, I see this in the rails console output:
Unpermitted parameters: person
According to the strong parameters documentation, this configuration should work, but I have also tried:
params.require(:adoption_request).permit(:person, person_attributes: [:first_name, :last_name])
which results in the same error ("Unpermitted parameters: person"), and
params.require(:adoption_request).permit!
works to allow the parameters through, but this is not an acceptable solution as it negates the whole purpose of using strong parameters.
What am I doing wrong?
Here is my Gemfile, in case it is helpful:
source 'https://rubygems.org'
ruby '2.0.0'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.0.3'
# Use postgresql as the database for Active Record
gem 'pg'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'
# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 1.2'
group :doc do
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', require: false
end
# Use Bootstrap
gem 'bootstrap-sass', '~> 3.3.4'
# Use Figaro to make using environment variables easier
gem 'figaro'
# Use Slim templating engine
gem "slim-rails"
# User authlogic for authentication system
gem 'authlogic'
# Use rails-bootstrap-forms to integrate rails form builder with bootstrap
gem 'bootstrap_form'
group :test do
# use MiniTest::Spec::DSL
gem 'minitest-spec-rails', '~> 4.7'
end
The app itself is more complex than this. I've simplified it to illustrate the problem.
Thanks in advance for your help!
You need to change this line
= f.fields_for #adoption_request.person do |owner_fields|
to
= f.fields_for :person do |owner_fields|
I would simply try building the Person object on save. Pass the first and last names up as hidden fields.
Otherwise I would give strong parameters a read.
if #adoption_request.save
#adoption_request.persons.build(first_name: #first_name, last_name: #last_name)

Adapter not set: default. Did you forget to setup?

I'm getting the same error when I execute my test in Rspec. DataMapper::RepositoryNotSetupError: Adapter not set: default. Did you forget to setup? I don't understand this error because I've set up Datamapper as it says in Datamapper webpage. I show you my code
vip_client-spec.rb
require 'spec_helper'
require 'data_mapper'
require 'dm-postgres-adapter'
require File.join(File.dirname(__FILE__), '..', '..', 'models', 'vip_client.rb')
describe VipClient do
before {
DataMapper.finalize.auto_upgrade!
}
describe "#insert_into_database" do
it "inserts clients into database from an array of hashes" do
list_clients = [
{name: "David", birthday: "13-12-1985", email: "daviddsrperiodismo#gmail.com"},
{name: "Javier", birthday: "05-05-1985", email: "javier#gmail.com"}
]
VipClient.insert_into_database(list_clients)
expect(VipClient.all.count).to eq(2)
end
end
end
vip_client.rb
class VipClient
include ::DataMapper::Resource
property :id, Serial
property :name, Text
property :birthday, Date
property :email, Text
def self.insert_into_database(list_clients)
end
end
app.rb
require 'sinatra'
require 'data_mapper'
require 'roo'
require 'pony'
# HELPERS
require './helpers/code'
require './helpers/check_birthday_users'
require './helpers/excel_parser'
# MODELS
require './models/vip_client.rb'
require './models/invitations.rb'
include Code
include CheckUsers
DataMapper.setup(:default, 'postgres://david:123456#localhost/usersmareta')
DataMapper.finalize.auto_upgrade!
And my gemfile is this
source "https://rubygems.org"
gem 'sinatra'
gem 'pg'
gem 'roo'
gem 'data_mapper'
gem 'dm-postgres-adapter'
gem 'pony'
group :development, :test do
gem 'rack-test'
gem 'rspec'
end
As I've said. when I do rspec the console gives me this:
Failure/Error: DataMapper.finalize.auto_upgrade!
DataMapper::RepositoryNotSetupError:
Adapter not set: default. Did you forget to setup?

Mongoid error in heroku: Database should be a Mongo::DB, not a nil class

I have a Sinatra app on heroku and it keeps crashing due to this error:
app/vendor/bundle/ruby/1.9.1/gems/mongoid-1.2.14/lib/mongoid/config.rb:52 in 'master': Database should be a Mongo::DB, not a nil class
I set up Mongoid 3.x according to the heroku instructions, and the app works on my local machine, so I'm not sure what's causing this problem. My gemfile looks like this:
source "https://rubygems.org"
ruby "1.9.3"
gem 'sinatra'
gem 'mongo'
gem 'mongoid'
gem 'bson_ext'
gem 'json'
gem 'nokogiri'
gem 'aws-s3', '0.6.2', :require => 'aws/s3'
gem 'sinatra-reloader'
gem 'debugger'
gem 'thin'
Here's my mongoid.yml:
development:
sessions:
default:
database: db
hosts:
- localhost:27017
production:
sessions:
default:
uri: <%= ENV['MONGOHQ_URL'] %>
options:
skip_version_check: true
safe: true
And here's my app file:
require 'bundler/setup'
require 'sinatra'
require 'json'
require 'mongo'
require 'mongoid'
Mongoid.load!('mongoid.yml', :production)
def get_connection
return #db_connection if #db_connection
db = URI.parse(ENV['MONGOHQ_URL'])
db_name = db.path.gsub(/^\//, '')
#db_connection = Mongo::Connection.new(db.host, db.port).db(db_name)
#db_connection.authenticate(db.user, db.password) unless (db.user.nil? || db.user.nil?)
#db_connection
end
db = get_connection
class Model1
include Mongoid::Document
field :name, :type => String
end
I shouldn't have to specify a database name since I'm using the uri field, so I'm not sure why the database if nil?

Getting a wrong argument type RSpec::Matchers::Matcher (expected Proc) error in Rspec when testing responses in Rails

I am trying to test my Rails 3.0.9 controller with Rspec 2.6.4 and Webrat 0.7.3. My controller looks like this:
#metrics_controller.rb
class MetricsController < ApplicationController
def show
#metric = Metric.all(:msrun_id => params[:id]).first
end
def index
#metrics = Metric.all
end
end
And my controller spec looks like this:
#metrics_controller_spec.rb
require 'spec_helper'
describe MetricsController do
describe "GET #index" do
it "should be successful" do
get :index
response.should be_success
end
end
describe "GET show" do
it 'contains an overview of a metric' do
get :show, :id => 1
response.should have_selector('title', :content => "Metric Overview")
end
end
end
This looks very similar to other examples I have seen in documentation, but when I run bundle exec rspec spec/controllers/metrics_controller_spec.rb I am getting some strange errors:
1) MetricsController GET #index should be successful
Failure/Error: response.should be_success
TypeError:
wrong argument type RSpec::Matchers::BePredicate (expected Proc)
# ./spec/controllers/metrics_controller_spec.rb:8
2) MetricsController GET show contains an overview of a metric
Failure/Error: response.should have_selector('title')
TypeError:
wrong argument type Webrat::Matchers::HaveSelector (expected Proc)
# ./spec/controllers/metrics_controller_spec.rb:16
It looks like something weird is going on with the response.should method. If I change the first example to something more verbose that doesn't call should on response like this:
response.success?.should == true
then the example works fine, but why would should be expecting a Proc? Any ideas about how I can fix this?
This is not an especially helpful answer, but I will put it in here in case someone else gets stuck on the same thing. I inherited the project from someone else, and they set it up to use both railties and rails. Changing the Gemfile to look like this:
source 'http://rubygems.org'
RAILS_VERSION = '~> 3.0.7'
DM_VERSION = '~> 1.1.0'
gem 'railties', RAILS_VERSION, :require => 'rails'
gem 'activesupport', RAILS_VERSION
gem 'actionpack', RAILS_VERSION
gem 'actionmailer', RAILS_VERSION
gem 'dm-rails', DM_VERSION
gem 'rspec-rails'
#other gems below
Instead of something like this:
source 'http://rubygems.org'
gem 'rails'
gem 'dm-rails', '~> 1.1.0'
gem 'rspec-rails'
#other gems below
along with changing the config/application.rb to require the railties instead of rails seemed to fix it. The key seemed to be using railties instead of all of rails along with dm-rails.

Load error when trying to include custom module

Same app, different problem. I'm working on an app using the Dan Benjamin "Meet Sinatra" screencast as a reference. I'm trying to include a custom authentication module, which is housed in a lib folder (lib/authentication.rb). I am requiring that line at the top of my code, but when I try to load the page, it claims there is no such file to load.
Any thoughts?
Here's the top of my main Sinatra file:
require 'sinatra'
require 'rubygems'
require 'datamapper'
require 'dm-core'
require 'lib/authorization'
DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/entries.db")
class Entry
include DataMapper::Resource
property :id, Serial
property :first_name, String
property :last_name, String
property :email, String
property :created_at, DateTime
end
# create, upgrade, or migrate tables automatically
DataMapper.auto_upgrade!
helpers do
include Sinatra::Authorization
end
And the actual Module:
module Sinatra
module Authorization
def auth
#auth ||= Rack::Auth::Basic::Request.new(request.env)
end
def unauthorized!(realm="Short URL Generator")
headers 'WWW-Authenticate' => %(Basic realm="#{realm}")
throw :halt, [ 401, 'Authorization Required' ]
end
def bad_request!
throw :halt, [ 400, 'Bad Request' ]
end
def authorized?
request.env['REMOTE_USER']
end
def authorize(username, password)
if (username=='topfunky' && password=='peepcode') then
true
else
false
end
end
def require_admin
return if authorized?
unauthorized! unless auth.provided?
bad_request! unless auth.basic?
unauthorized! unless authorize(*auth.credentials)
request.env['REMOTE_USER'] = auth.username
end
def admin?
authorized?
end
end
end
Then, on any of the handlers I want to protect, I put "require_admin."
Assuming you're using Ruby 1.9, the default $LOAD_PATH no longer includes the current directory. So while statements like require 'sinatra' work just fine (because those gems are in $LOAD_PATH), Ruby doesn't know that your lib/authorization file is located relative to your main Sinatra file.
You can add the Sinatra file's directory to the load path, and then your require statements should work fine:
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'sinatra'
require 'rubygems' # Not actually needed on Ruby 1.9
require 'datamapper'
require 'dm-core'
require 'lib/authorization'
Personnaly, I use a "relative" path since I work with Ruby 1.9.2 :
require 'sinatra'
require 'rubygems' # Not actually needed on Ruby 1.9
require 'datamapper'
require 'dm-core'
require './lib/authorization'
But I never check what would happen if my code should work on Ruby 1.8.6 again.

Resources