How to extend DataMapper::Resource with custom method - ruby

I have following code:
module DataMapper
module Resource
##page_size = 25
attr_accessor :current_page
attr_accessor :next_page
attr_accessor :prev_page
def first_page?
#prev_page
end
def last_page?
#next_page
end
def self.paginate(page)
if(page && page.to_i > 0)
#current_page = page.to_i - 1
else
#current_page = 0
end
entites = self.all(:offset => #current_page * ##page_size, :limit => ##page_size + 1)
if #current_page > 0
#prev_page = #current_page
end
if entites.size == ##page_size + 1
entites.pop
#next_page = (#current_page || 1) + 2
end
entites
end
end
end
Then I have call of #paginate:
#photos = Photo.paginate(params[:page])
And getting following error:
application error
NoMethodError at /dashboard/photos/
undefined method `paginate' for Photo:Class
In Active record this concept works fine for me... I'am using JRuby for notice. What I'am doing wrong?

Andrew,
You can think of DataMapper::Resource as the instance (a row) and of DataMapper::Model as the class (a table). Now to alter the default capabilities at either the resource or the model level, you can either append inclusions or extensions to your model.
First you will need to wrap your #paginate method in a module. I've also added a probably useless #page method to show how to append to a resource in case you ever need to.
module Pagination
module ClassMethods
def paginate(page)
# ...
end
end
module InstanceMethods
def page
# ...
end
end
end
In your case, you want #paginate to be available on the model, so you would do:
DataMapper::Model.append_extensions(Pagination::ClassMethods)
If you find yourself in need of adding default capabilities to every resource, do:
DataMapper::Model.append_inclusions(Pagination::InstanceMethods)
Hope that helps!

Related

Capybara.page not in scope after extending capybara-screenshot's after_failed_example method

I'm trying to override the after_failed_example method so I can inflict some custom file naming on our screenshots. I'm loading the module as an initializer.
So far, so good, but the Capybara.page.current_url is blank, making me think I need to require something additional?
require "capybara-screenshot/rspec"
module Capybara
module Screenshot
module RSpec
class << self
attr_accessor :use_description_as_filename
attr_accessor :save_html_file
end
self.use_description_as_filename = true
self.save_html_file = true
def self.after_failed_example(example)
if example.example_group.include?(Capybara::DSL) # Capybara DSL method has been included for a feature we can snapshot
Capybara.using_session(Capybara::Screenshot.final_session_name) do
puts ">>>> Capybara.page.current_url: " + Capybara.page.current_url.to_s
if Capybara::Screenshot.autosave_on_failure && failed?(example) && Capybara.page.current_url != ''
saver = Capybara::Screenshot.new_saver(Capybara, Capybara.page, Capybara::Screenshot.save_html_file?, set_saver_filename_prefix(example))
saver.save
example.metadata[:screenshot] = {}
example.metadata[:screenshot][:html] = saver.html_path if saver.html_saved?
example.metadata[:screenshot][:image] = saver.screenshot_path if saver.screenshot_saved?
end
end
end
private
def self.set_saver_filename_prefix(example)
return example.description.to_s.gsub(" ", "-") if Capybara::Screenshot.use_description_as_filename?
return Capybara::Screenshot.filename_prefix_for(:rspec, example)
end
end
end
end
end
This is successfully overriding the capybara-screenshot/rspec method, and any of the Capybara::Screenshot static information is accessible, but not Capybara session related information (afa I can tell).
For example, Capybara.page.current_url.to_s is null when overridden, but present when not.
I was missing a require (kind of silly mistake):
require 'capybara/rspec'

bad char after creating a Database from csv

I am trying to create a database using mongoid but it fails to find the create method. I am trying to create 2 databases based on csv files:
extract_data class:
class ExtractData
include Mongoid::Document
include Mongoid::Timestamps
def self.create_all_databases
#cbsa2msa = DbForCsv.import!('./share/private/csv/cbsa_to_msa.csv')
#zip2cbsa = DbForCsv.import!('./share/private/csv/zip_to_cbsa.csv')
end
def self.show_all_database
ap #cbsa2msa.all.to_a
ap #zip2cbsa.all.to_a
end
end
the class DbForCSV works as below:
class DbForCsv
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Attributes::Dynamic
def self.import!(file_path)
columns = []
instances = []
CSV.foreach(file_path, encoding: 'iso-8859-1:UTF-8') do |row|
if columns.empty?
# We dont want attributes with whitespaces
columns = row.collect { |c| c.downcase.gsub(' ', '_') }
next
end
instances << create!(build_attributes(row, columns))
end
instances
end
private
def self.build_attributes(row, columns)
attrs = {}
columns.each_with_index do |column, index|
attrs[column] = row[index]
end
ap attrs
attrs
end
end
I am not aware of all fields and it may change in time. that's why I have create database and generic mehtods.
I have also another issue after having fixed the 'create!' issue.
I am using the encoding to make sure only UTF8 char are handled but I still see:
{
"zip" => "71964",
"cbsa" => "31680",
"res_ratio" => "0.086511098",
"bus_ratio" => "0.012048193",
"oth_ratio" => "0.000000000",
"tot_ratio" => "0.082435345"
}
when doing 'ap attrs' in the code. how to make sure that 'zip' -> 'zip'
Thanks
create! is a class method but you're trying to call it as an instance method. Your import! method shouldn't be an instance method either, it should be a class method since it produces instances of your class:
def self.import!(file_path)
#-^^^^
# everything else would be the same...
end
You'd also make build_attributes a class method since it is just a helper method for another class method:
def self.build_attributes
#...
end
And then you don't need that odd looking new call when using import!:
def self.create_all_databases
#cbsa2msa = DbForCsv.import!('./share/private/csv/cbsa_to_msa.csv')
#zip2cbsa = DbForCsv.import!('./share/private/csv/zip_to_cbsa.csv')
end

Test helpers with RSpec in Padrino (Sinatra)

I'm trying to test a helper in a Padrino (Sinatra) app. My helper method is itself calling Padrino core helper methods but they are undefined. The error appears only in RSpec, while the app works fine. So the way I'm including my helper in RSpec makes it loose "Padrino scope" but I don't know how to bring Padrino helper's scope properly in my RSpec environment.
My helper:
module AdminHelper
Sort = Struct.new(:column, :order)
def sort_link(model, column)
order = sorted_by_this?(column) ? 'desc' : 'asc'
link_to mat(model, column), url(:pages, :index, sort: column, order: order)
end
def sorted_by_this?(column)
column.to_s == #sort.column && #sort.order == 'asc'
end
end
Lenstroy::Admin.helpers AdminHelper
My spec:
describe AdminHelper do
before(:all) do
class AdminHelperClass
include AdminHelper
end
end
subject(:helper) { AdminHelperClass.new }
describe '#sort_link' do
context "with :pages and :title parameters" do
before do
sort = AdminHelperClass::Sort.new('title', 'asc')
helper.instance_variable_set('#sort', sort)
end
subject { helper.sort_link(:pages, :title) }
it { should match(/<a href=([^ ]+)pages/) }
end
end
end
Results in error:
1) AdminHelper#sort_link with :pages and :title parameters
Failure/Error: subject { helper.sort_link(:pages, :title) }
NoMethodError:
undefined method `mat' for #<AdminHelperClass:0x007f1d951dc4a0>
Including a helper where mat is defined doesn't work, as one method is dependent on another helper and it goes on and on...
Update
In my spec helper I have:
def app(app = nil, &blk)
#app ||= block_given? ? app.instance_eval(&blk) : app
#app ||= Lenstroy::Admin
#app.register Padrino::Helpers
#app.register Padrino::Rendering
#app
end
in my spec I have:
it "returns link to resource with sort parameters" do
app do
get '/' do
sort_link(:pages, :title)
end
end
get "/"
last_response.body.should =~ /<a href=([^ >]+)pages/
end
And now tests fail, last_response.body is ''.
Method #mat is defined in Padrino::Admin::Helpers::ViewHelpers. You can do
class AdminHelperClass
include Padrino::Admin::Helpers::ViewHelpers
include AdminHelper
end
Update:
If your methods are really dependent on all these routes and helpers you should consider doing full mockup of your app like this:
def mock_app(base=Padrino::Application, &block)
#app = Sinatra.new(base, &block)
#app.register Padrino::Helpers
#app.register Padrino::Rendering
# register other things
end
def app
Rack::Lint.new(#app)
end
mock_app do
get '/' do
sort_link(my_model, my_column)
end
end
get "/"
assert_equal "some test text", body
Here's how it's done in padrino-admin: https://github.com/padrino/padrino-framework/blob/master/padrino-admin/test/test_admin_application.rb
I was having the same problem (and getting very frustrated tracking down the modules and including them). So far, I've got my specs working by:
1) Explicitly defining my module (as explained in how to use padrino helper methods in rspec)
module MyHelper
...
end
MyApp::App.helpers MyHelper
2) Automatically including helpers at the top of my spec. (Right now I only have one helper spec, but in the future I might try to move this into spec_helper.rb.)
describe MyHelper do
let(:helpers) { Class.new }
before { MyApp::App.included_modules.each { |m| helpers.extend m } }
subject { helpers }
it 'blah' do
expect(subject.helper_method).to eq 'foo'
end
end

Rails 4 strong parameters ActiveModel::ForbiddenAttributesError

For some reason in my current controller I am getting ActiveModel::ForbiddenAttributesError even though I believe I am using strong parameters just fine. Albeit I am using permit! for the time being to permit all model attributes. See code below, what am I missing
class HeuristicsController < ApplicationController
def index
#heuristics = Heuristic.order(:name).page params[:page]
#heuristic = Heuristic.new
end
def create
#heuristic = Heuristic.new(params[:heuristic])
if #heuristic.save
redirect_to action: 'index', :flash => {:success => "New heuristic created!" }
else
render 'new'
end
end
def new
#title = "Heuristic"
#heuristic = Heuristic.new
end
private
def heuristic_params
params.require(:heuristic).permit!
end
end
i think you did not fully understand the way that strong-params work...
you have a method
def heuristic_params
params.require(:heuristic).permit!
end
and you are not using it
Heuristic.new(params[:heuristic])

How do I integrate a module?

UPDATE: I changed my model a bit, but it still do not works. I get the following error message: ActionController::RoutingError (undefined local variable or method `stop_words_finder' for #< Class:0x007facb57f6908 >)
models/pool.rb
class Pool < ActiveRecord::Base
include StopWords
attr_accessible :fragment
def self.delete_stop_words(data)
words = data.scan(/\w+/)
stop_words = stop_words_finder
key_words = words.select { |word| !stop_words.include?(word) }
pool_frag = Pool.create :fragment => key_words.join(' ')
end
end
lib/stop_words.rb
module StopWords
def stop_words_finder
%w{house}
end
end
controllers/tweets_controller.rb
class TweetsController < ApplicationController
def index
#tweets = Pool.all
respond_with(#tweets)
end
end
stop_words = :stop_words_finder
assigns the symbol :stop_words_finder to stop_words. What you want to do is call the stop_words_finder method that you included from Stopwords, which will return the array. In this case, all you have to do is remove the colon.
stop_words = stop_words_finder
Add this to your model to make stop_words_finder available to Pool instances:
include StopWords
Pool.new.stop_words_finder will work
To make stop_words_finder available to the Pool class, use extend:
extend StopWords
Pool.stop_words_finder will work.
Also, why on earth are you creating an instance of Pool inside the Pool class definition?
As it stands you're including the module into your ApplicationController class. This has absolutely no effect on the Pool class. In addition creating instances of the Pool class inside its definition is rather unorthodox - do you really want to create a new row in your database everytime the code to your app is loaded? I would refactor things along these lines
class Pool < ActiveRecord::Base
class << self
include StopWords
def create_from_data(data)
words = data.scan(/\w+/)
stop_words = stop_words_finder
key_words = words.select { |word| !stop_words.include?(word) }
pool = Pool.create :pooltext => key_words.join(' ')
end
end
end
You'd then call Pool.create_from_data %q{Ich gehe heute schwimmen. Und du?} when you want to create it.

Resources