Routing Error: No route matches [GET] "/api/v1/courts/by_coordinates/41.89400864" - ruby

I have this error when I try to search in url by coordinates (saved as :latitude and :longitude in db using geocoder gem):
No route matches [GET] "/api/v1/courts/by_coordinates/41.89400864"
Here the code that I'm using.
module API
module V1
class Courts < Grape::API
version 'v1' # path-based versioning by default
format :json # We don't like xml anymore
resource :courts do
desc "Courts index"
get do
courts = Court.all
present courts, with: API::Entities::Court
end
desc "Search by address or city"
params do
requires :address, :type => String, :desc => "Court Address"
end
get "by_address/:address" do
courts = Court.near(params[:address])
present courts, with: API::Entities::Court
end
desc "Search by address or city and range"
params do
requires :address, :type => String, :desc => "Court Address"
requires :distance, :type => Integer, :desc => "Range of Distance"
end
get "by_address/:address/:distance" do
courts = Court.near(params[:address], params[:distance])
present courts.sort_by(&:distance), with: API::Entities::Court
end
desc "Search by coordinates"
params do
requires :latitude, :type => BigDecimal, :desc => "Court Latitude"
end
get "by_coordinates/:latitude" do
courts = Court.near(params[:latitude])
present courts, with: API::Entities::Court
end
end
end
end
end
I don't understand why if I use the research by address it works, but if I simply change the address with latitude params it stops to work.
Someone can halp me, please? Thank you in advance!

Related

Syntax for declaring resource paths in Grape

I am looking for clarification on the syntax to declare API resource paths in Grape. The example below declares the resource paths "/items", "/items/:id", "/objects", and "/objects/:id". What I do not undestand is why the definition for "/items/:id" returns null?
class API < Grape::API
format :json
default_format :json
rescue_from :all, backtrace: true
resource :items do
desc "Returns an array of all items."
get do
ITEMS.find.to_a
end
desc "Returns an item by its id."
get '/:id' do
# hardcoding the document id returns the correct document
# ITEMS.find_one( "item_id" => 2519 )
# using the path parameter :id returns null, why???
ITEMS.find_one( "item_id" => params[:id] )
end
end
resource :objects do
desc "Returns an array of all objects."
get do
OBJECTS.find.to_a
end
##
# using the route_param syntax correctly returns the document
# resource path /objects/:id
##
desc "Returns an object by its id."
params do
requires :id, type: Integer
end
route_param :id do
get do
OBJECTS.find_one( "object_id" => params[:id] )
end
end
end
end
Your use of resource and route methods is ok.
You have a problem with parameter processing - params[:id] is a String by default. Your example hard-coded value that works is aFixnum (integer).
Probably your (not shown) code that queries the list on ITEMS is looking up integer values.
You could use ITEMS.find_one( "item_id" => params[:id].to_i ) to convert the param inline.
However, you probably should use a params description block to get Grape to convert for you, as you already are for OBJECTS:
desc "Returns an item by its id."
params do
requires :id, type: Integer
end
get '/:id' do
ITEMS.find_one( "item_id" => params[:id] )
end

Multiple Route Params in Grape

How do you get multiple route params in Grape to work in grape?
I can make this route work:
.../api/company/:cid
But when I try this:
.../api/company/:cid/members
.../api/company/:cid/members/:mid
I get errors.
Here's the code that works.
resource 'company' do
params do
optional :start_date, type: Date, desc: "Start date of range."
optional :end_date, type: Date, desc: "End date of range."
end
route_param :cid do
get do
{company_id: params[:cid]}
end
end
class API::Company < Grape::API
resource :company do
route_param :cid do
desc "GET"
params do
# your params
end
get '/' do # => '.../api/company/:cid
# process get
end
resources :members do
desc "GET"
params do
# your params
end
get '/' do # => '.../api/company/:cid/members/'
# process get
end
route_param :mid do
desc "GET"
params do
# your params
end
get '/' do # => '.../api/company/:cid/members/:mid'
# process get
end
end
end
end
end
end
You can do that that way. Or you can create two different resources file and mount Members to Company. Like so:
# api/company.rb
class API::Company < Grape::API
resource :company do
route_param :cid do
desc "GET"
params do
# your params
end
get '/' do # => '.../api/company/:cid
# process get
end
mount API::Members
end
end
end
# api/member.rb
class API::Member < Grape::API
resources :members do
desc "GET"
params do
# your params
end
get '/' do # => '.../api/company/:cid/members/'
# process get
end
route_param :mid do
desc "GET"
params do
# your params
end
get '/' do # => '.../api/company/:cid/members/:mid'
# process get
end
end
end
Hope that helps
Another way to do that is using a regexp to validate the ids.
resource 'company' :requirements => { :id => /[0-9]*/, :mid => /[0-9]*/ } do
get '/:id' do
# returns company
end
get ":id/members" do
members = Company.find_by_id(params[:id]).members
present members, :with => Members::MemberResponseEntity
end
get ":id/members/:mid" do
member = Member.find_by_id(params[:mid])
present member, :with => Members::MemberResponseEntity
end
end

Ruby Sinatra + Sequel constraint error handling

What is the right way to handle exceptions coming from the model in Sequel? Particularly the thing I'm running into is when the unique constraint is applied to the login. The exception in this case appears to be coming from SQLite itself instead of Sequel which means it's not getting handled by "errors".
This is the error I'm getting after trying to create a user with a "non-unique" login:
Sequel::DatabaseError at /user/create
SQLite3::ConstraintException: column login is not unique
file: database.rb location: close line: 97
Here is my abbreviated code:
require 'sinatra'
require 'sequel'
DB.create_table :users do
primary_key :id
String :login, :key => true, :length => (3..40), :required => true, :unique => true
String :hashed_password, :required => true
String :salt
DateTime :created_at, :default => DateTime.now
end
class User < Sequel::Model
# password authentication code
end
get '/user/create' do
slim :user_create
end
post '/user/create' do
user = User.new
user.login = params['login']
user.password = params['password']
if user.save
'User created'
else
tmp = []
user.errors.each do |e|
tmp << (e.join('<br/>'))
end
tmp
end
end
You probably want to use the validation_helpers plugin and use validates_unique :login inside the validate method.
Add the code below to handle sequel errors in sinatra.
The error block in sinatra will handle any errors thrown in one of your routes. You can specify the type of error in the first line in order to only handle those types of errors.
error Sequel::Error do
e = env['sinatra.error']
content_type :json
status(400)
return {
message: e.message
}.to_json
end
If you wanted to handle all errors, you would insert the following block of code.
error Exception do
e = env['sinatra.error']
content_type :json
status(400)
return {
message: e.message
}.to_json
end
You can combine many of these blocks so that you are handling different types of errors differently.
First - use validation plugin
# models/account.rb
Sequel::Model.plugin :validation_helpers
class Account < Sequel::Model
def validate
super
validates_unique :login
end
end
Next - handle error in app
# app.rb
...
begin
Account.create
rescue => e
# do what you need
end
...

Sinatra: DB Authentication with Sessions

I am writing a small sinatra application that I am integrating with Authlogic (following https://github.com/ehsanul/Sinatra-Authlogic-Template)
Everything works except for when I try to login. I get the following error:
NameError at /login
undefined local variable or method `active' for #<User:0x000001040208f0>
I am including the authlogic gem versus including it as a vendor. So my Sinatra app is not exactly the same as the one on Github.
Any and all inquiries will be MUCH appreciated!! Thanks!
Found out my issue.
Here is the model according to the Github page:
class User < ActiveRecord::Base
acts_as_authentic do |c|
# Bcrypt is recommended
#crypto_provider = Authlogic::CryptoProviders::BCrypt
c.perishable_token_valid_for( 24*60*60 )
c.validates_length_of_password_field_options =
{:on => :update, :minimum => 6, :if => :has_no_credentials?}
c.validates_length_of_password_confirmation_field_options =
{:on => :update, :minimum => 6, :if => :has_no_credentials?}
end
def active?
active
end
def has_no_credentials?
crypted_password.blank? #&& self.openid_identifier.blank?
end
def send_activation_email
Pony.mail(
:to => self.email,
:from => "no-reply#domain.tld",
:subject => "Activate your account",
:body => "You can activate your account at this link: " +
"http://domain.tld/activate/#{self.perishable_token}"
)
end
def send_password_reset_email
Pony.mail(
:to => self.email,
:from => "no-reply#domain.tld",
:subject => "Reset your password",
:body => "We have recieved a request to reset your password. " +
"If you did not send this request, then please ignore this email.\n\n" +
"If you did send the request, you may reset your password using the following link: " +
"http://domain.tld/reset-password/#{self.perishable_token}"
)
end
end
I removed all of the mail methods but my script was failing on the active? method because it was looking for an active column in the users table. Since I am unable to append this column to the table (due to data integrity with another system) I simply told my method to return true
My User.rb
class UserSession < Authlogic::Session::Base
end
class User < ActiveRecord::Base
acts_as_authentic do |c|
end
def active?
return true
end
end
Hope this helps someone!

Rails audit system with both ActiveResource and ActiveRecord

I have a huge project with both of ActiveRecord and ActiveResource models. I need to implement logging of user activity with these models and also to log changes of model attributes (save object state or somthing like that). Changes can made by users or cron rake tasks.
I also must have possibility to search any data by date , any field ..etc
Will be nice also to generate readable messages with last activity , for example
User Bob change his password to * and email to ** at 2011-08-12 08:12
Staff Jeff added new partner: Company name at 2011-08-12 08:13
Admin Jack deleted product : Product name at 2011-09-12 11:11
Client Sam ordered new service : Service name at 2011-09-12 11:12
Does anybody implement such logging? Ideas? Advices?
should I use gems or can I do all the logic with observers not changing models?
I liked gem https://github.com/airblade/paper_trail can anybody say how can I make it work with activeresource ?
You are looking for
https://github.com/collectiveidea/acts_as_audited
Few open source projects use that plugin I think Red Mine as well as The Foreman.
Edit: Unfortunately it can do only ActiveRecord, not ActiveResource.
Fivell, I just saw this question and don't have time to work up alterations this evening before the bounty expires, so I'll give you my auditing code that works with ActiveRecord and should work with ActiveResource, perhaps with a few tweaks (I don't use ARes often enough to know offhand). I know the callbacks we use are there, but I'm not sure if ARes has ActiveRecord's dirty attribute changes tracking.
This code logs each CREATE/UPDATE/DELETE on all models (excepting CREATEs on the audit log model and any other exceptions you specify) with the changes stored as JSON. A cleaned backtrace is also stored so you can determine what code made the change (this captures any point in your MVC as well as rake tasks and console usage).
This code works for console usage, rake tasks, and http requests, although generally only the last one logs the current user. (If I recall correctly, the ActiveRecord observer that this replaced did not work in rake tasks or the console.) Oh, this code comes from a Rails 2.3 app - I have a couple Rails 3 apps, but I haven't needed this kind of auditing for them yet.
I don't have code that builds a nice display of this information (we only dig into the data when we need to look into an issue), but since the changes are stored as JSON it should be fairly straightforward.
First, we store the current user in User.current so it is accessible everywhere, so in app/models/user.rb:
Class User < ActiveRecord::Base
cattr_accessor :current
...
end
The current user is set in the application controller for each request like so (and does not cause concurrency issues):
def current_user
User.current = session[:user_id] ? User.find_by_id(session[:user_id]) : nil
end
You could set User.current in your rake tasks if it made sense to.
Next, we define the model to store the audit info app/models/audit_log_entry.rb - you'll want to customize IgnoreClassesRegEx to fit any models you don't want audited:
# == Schema Information
#
# Table name: audit_log_entries
#
# id :integer not null, primary key
# class_name :string(255)
# entity_id :integer
# user_id :integer
# action :string(255)
# data :text
# call_chain :text
# created_at :datetime
# updated_at :datetime
#
class AuditLogEntry < ActiveRecord::Base
IgnoreClassesRegEx = /^ActiveRecord::Acts::Versioned|ActiveRecord.*::Session|Session|Sequence|SchemaMigration|CronRun|CronRunMessage|FontMetric$/
belongs_to :user
def entity (reload = false)
#entity = nil if reload
begin
#entity ||= Kernel.const_get(class_name).find_by_id(entity_id)
rescue
nil
end
end
def call_chain
return if call_chain_before_type_cast.blank?
if call_chain_before_type_cast.instance_of?(Array)
call_chain_before_type_cast
else
JSON.parse(call_chain_before_type_cast)
end
end
def data
return if data_before_type_cast.blank?
if data_before_type_cast.instance_of?(Hash)
data_before_type_cast
else
JSON.parse(data_before_type_cast)
end
end
def self.debug_entity(class_name, entity_id)
require 'fastercsv'
FasterCSV.generate do |csv|
csv << %w[class_name entity_id date action first_name last_name data]
find_all_by_class_name_and_entity_id(class_name, entity_id,
:order => 'created_at').each do |a|
csv << [a.class_name, a.entity_id, a.created_at, a.action,
(a.user && a.user.first_name), (a.user && a.user.last_name), a.data]
end
end
end
end
Next we add some methods to ActiveRecord::Base to make the audits work. You'll want to look at the audit_log_clean_backtrace method and modify for your needs. (FWIW, we put additions to existing classes in lib/extensions/*.rb which are loaded in an initializer.) In lib/extensions/active_record.rb:
class ActiveRecord::Base
cattr_accessor :audit_log_backtrace_cleaner
after_create :audit_log_on_create
before_update :save_audit_log_update_diff
after_update :audit_log_on_update
after_destroy :audit_log_on_destroy
def audit_log_on_create
return if self.class.name =~ /AuditLogEntry/
return if self.class.name =~ AuditLogEntry::IgnoreClassesRegEx
audit_log_create 'CREATE', self, caller
end
def save_audit_log_update_diff
#audit_log_update_diff = changes.reject{ |k,v| 'updated_at' == k }
end
def audit_log_on_update
return if self.class.name =~ AuditLogEntry::IgnoreClassesRegEx
return if #audit_log_update_diff.empty?
audit_log_create 'UPDATE', #audit_log_update_diff, caller
end
def audit_log_on_destroy
return if self.class.name =~ AuditLogEntry::IgnoreClassesRegEx
audit_log_create 'DESTROY', self, caller
end
def audit_log_create (action, data, call_chain)
AuditLogEntry.create :user => User.current,
:action => action,
:class_name => self.class.name,
:entity_id => id,
:data => data.to_json,
:call_chain => audit_log_clean_backtrace(call_chain).to_json
end
def audit_log_clean_backtrace (backtrace)
if !ActiveRecord::Base.audit_log_backtrace_cleaner
ActiveRecord::Base.audit_log_backtrace_cleaner = ActiveSupport::BacktraceCleaner.new
ActiveRecord::Base.audit_log_backtrace_cleaner.add_silencer { |line| line =~ /\/lib\/rake\.rb/ }
ActiveRecord::Base.audit_log_backtrace_cleaner.add_silencer { |line| line =~ /\/bin\/rake/ }
ActiveRecord::Base.audit_log_backtrace_cleaner.add_silencer { |line| line =~ /\/lib\/(action_controller|active_(support|record)|hoptoad_notifier|phusion_passenger|rack|ruby|sass)\// }
ActiveRecord::Base.audit_log_backtrace_cleaner.add_filter { |line| line.gsub(RAILS_ROOT, '') }
end
ActiveRecord::Base.audit_log_backtrace_cleaner.clean backtrace
end
end
Finally, here are the tests we have on this - you'll need to modify the actual test actions of course. test/integration/audit_log_test.rb
require File.dirname(__FILE__) + '/../test_helper'
class AuditLogTest < ActionController::IntegrationTest
def setup
end
def test_audit_log
u = users(:manager)
log_in u
a = Alert.first :order => 'id DESC'
visit 'alerts/new'
fill_in 'alert_note'
click_button 'Send Alert'
a = Alert.first :order => 'id DESC', :conditions => ['id > ?', a ? a.id : 0]
ale = AuditLogEntry.first :conditions => {:class_name => 'Alert', :entity_id => a.id }
assert_equal 'Alert', ale.class_name
assert_equal 'CREATE', ale.action
end
private
def log_in (user, password = 'test', initial_url = home_path)
visit initial_url
assert_contain 'I forgot my password'
fill_in 'email', :with => user.email
fill_in 'password', :with => password
click_button 'Log In'
end
def log_out
visit logout_path
assert_contain 'I forgot my password'
end
end
And test/unit/audit_log_entry_test.rb:
# == Schema Information
#
# Table name: audit_log_entries
#
# id :integer not null, primary key
# class_name :string(255)
# action :string(255)
# data :text
# user_id :integer
# created_at :datetime
# updated_at :datetime
# entity_id :integer
# call_chain :text
#
require File.dirname(__FILE__) + '/../test_helper'
class AuditLogEntryTest < ActiveSupport::TestCase
test 'should handle create update and delete' do
record = Alert.new :note => 'Test Alert'
assert_difference 'Alert.count' do
assert_difference 'AuditLogEntry.count' do
record.save
ale = AuditLogEntry.first :order => 'created_at DESC'
assert ale
assert_equal 'CREATE', ale.action, 'AuditLogEntry.action should be CREATE'
assert_equal record.class.name, ale.class_name, 'AuditLogEntry.class_name should match record.class.name'
assert_equal record.id, ale.entity_id, 'AuditLogEntry.entity_id should match record.id'
end
end
assert_difference 'AuditLogEntry.count' do
record.update_attribute 'note', 'Test Update'
ale = AuditLogEntry.first :order => 'created_at DESC'
expected_data = {'note' => ['Test Alert', 'Test Update']}
assert ale
assert_equal 'UPDATE', ale.action, 'AuditLogEntry.action should be UPDATE'
assert_equal expected_data, ale.data
assert_equal record.class.name, ale.class_name, 'AuditLogEntry.class_name should match record.class.name'
assert_equal record.id, ale.entity_id, 'AuditLogEntry.entity_id should match record.id'
end
assert_difference 'AuditLogEntry.count' do
record.destroy
ale = AuditLogEntry.first :order => 'created_at DESC'
assert ale
assert_equal 'DESTROY', ale.action, 'AuditLogEntry.action should be CREATE'
assert_equal record.class.name, ale.class_name, 'AuditLogEntry.class_name should match record.class.name'
assert_equal record.id, ale.entity_id, 'AuditLogEntry.entity_id should match record.id'
assert_nil Alert.find_by_id(record.id), 'Alert should be deleted'
end
end
test 'should not log AuditLogEntry create entry and block on update and delete' do
record = Alert.new :note => 'Test Alert'
assert_difference 'Alert.count' do
assert_difference 'AuditLogEntry.count' do
record.save
end
end
ale = AuditLogEntry.first :order => 'created_at DESC'
assert_equal 'CREATE', ale.action, 'AuditLogEntry.action should be CREATE'
assert_equal record.class.name, ale.class_name, 'AuditLogEntry.class_name should match record.class.name'
assert_equal record.id, ale.entity_id, 'AuditLogEntry.entity_id should match record.id'
assert_nil AuditLogEntry.first(:conditions => { :class_name => 'AuditLogEntry', :entity_id => ale.id })
if ale.user_id.nil?
u = User.first
else
u = User.first :conditions => ['id != ?', ale.user_id]
end
ale.user_id = u.id
assert !ale.save
assert !ale.destroy
end
end
https://github.com/collectiveidea/acts_as_audited
and
https://github.com/airblade/paper_trail
are both great solutions for ActiveRecord only, but since much of ActiveRecord has been extracted to ActiveModel, it's likely to be reasonable to extend either to support ActiveResource as well, at least for read-only support. I looked through the Github network graphs and googled around and there doesn't appear to be any ongoing development of such a solution, nevertheless I expect it will be easier to implement on top of one of these two plugins than starting from scratch. paper_trail appears to be under more active development and has some commits for Rails 3.1, so it may be more up to date with Rails internals and easier to extend, but that's just a gut instinct—I'm not familiar with the internals of either.
The acts_as_audited gem should work well for you:
https://github.com/collectiveidea/acts_as_audited
And as far as ActiveResource is considered, it will also be a model in some other application. You can use the gem at the server side, and you don't need to audit it at the client side. All the CRUD operations using ActiveResource would finally translate to CRUD operations on the ActiveRecord (on server side).
So probably you need to look at it from a distance, and the same solution would apply in both the cases, but at different places.
for tracking user activity(CRUD ), i've created a class inherits from Logger, and now I am planing to write a litle plugin for tracking user that i can use for any ROR application built. I have already checked if there is a plugin like that but I didn’t see. I guess there are many gem like paper-trail, acts_as_audited or itslog but i prefer to use a plugin. Any suggestions?
Here is a link that might help you : http://robaldred.co.uk/2009/01/custom-log-files-for-your-ruby-on-rails-applications/comment-page-1/#comment-342
nice coding

Resources