I'm hosting my Couch instance on iriscouch.com and doing some testing with a simple Sinatra app, using CouchRest Model.
Here's a simple model I'm using:
class User < CouchRest::Model::Base
property :first_name, String
property :last_name, String
timestamps!
design do
view :by_first_name
end
end
I'm successfully creating new users with:
User.create(:first_name => "Stonewall", :last_name => "Jackson")
Executing User.by_first_name.all results in this HTTP request:
http://test_admin:pwd#testytest.iriscouch.com:80/blt/_design/User/_view/by_first_name?include_docs=true&reduce=false
"Accept"=>"application/json"
"Accept-Encoding"=>"gzip, deflate"
"Content-Type"=>"application/json"
This is executed by RestClient, via CouchRest. No problems there.
But when I try to curlthis URL, I get complaints from Couch about the include_docs parameter:
{"error":"query_parse_error","reason":"Query parameter `include_docs` is invalid for reduce views."}
I'd like to understand what's going on here. Why is include_docsa problem only when using curl?
One difference is that your URL now contains a question mark. If you don't protect the URL in the shell, it will be interpreted as a special character.
If you want a simpler way to test your services, you can use RESTClient instead of curl.
Related
For testing, I send a Rack::Request straight to the app, not using the server.
def request_via_API( app, method, path, params={} ) # app should be API
env = Rack::MockRequest.env_for( path, {:method => method, :params=>params} )
app.handle Rack::Request.new(env)
end
works great for testing direct input, but I'm stymied by file upload. My real system works great from the browser with a file upload. But now I want to test it via the API, and don't know how to get the file contents into the request via any of the Rack classes/methods. (I tried making sense of Rack::Test::UploadedFile but didn't succeed).
Thanks, Alistair
You were definitely on the right path. You can even use your function request_via_API without any modifications, e.g.:
request_via_API(app, 'POST', '/', {
:field => "value",
:text_source => Rack::Multipart::UploadedFile.new(PATH_TO_YOUR_FILE, MIME_TYPE_OF_YOUR_FILE)
})
This means you need to have some file somewhere. If you use fixtures, your test upload file should be around them. You can omit MIME time, but it defaults to text/plain.
If you use barebones Rack, you get the following hash after calling Rack::Multipart.parse_multipart:
{
"field" => "value",
"text_source" => {
:filename => File.basename(PATH_TO_YOUR_FILE),
:type => MIME_TYPE_OF_YOUR_FILE,
:name => "text_source",
:tempfile => Tempfile.new("RackMultipart"), # copied from PATH_TO_YOUR_FILE
:head => "Content-Disposition: form-data; name=\"text_source\"; filename=\"#{File.basename(PATH_TO_YOUR_FILE)}\"\r\n" +
"Content-Type: #{MIME_TYPE_OF_YOUR_FILE}\r\n" +
"Content-Length: #{BYTESIZE_OF_YOUR_FILE}\r\n"
}
}
The text_source key can have any other name, of course.
Rack::MockRequest#env_for automatically tries to create multipart form data request if:
HTTP method is not GET
there is no :input option provided
:params option is a Hash
:params option values contain at least one instance of Rack::Multipart::UploadedFile
You can see the details in the source code here and here.
I think relying on multipart request generation by Rack::MockRequest and Rack::Multipart is useful only for mocking HTML forms with file upload and file upload mechanisms that act the same. So, there's no need to use Rack::Multipart#build_multipart or Rack::Multipart::Generator directly.
If you have more complicated multipart scenarios or different file upload mechanism, you must pass opts argument with :input key instead of :params to Rack::MockRequest#env_for. How you generate that value for :input is your problem as far as Rack mocking capabilities are concerned. It only wraps it in StringIO if it is a String as you can see here. Otherwise, it is the same thing that will be passed as rack.input in the Rack environment hash and therefore it must conform to the Rack input stream spec (i.e., be an IO-like object).
Because this was also quite a challenge for me and I used it as an exercise to deepen my knowledge of Rack I created a simple project on GitHub to explore this file upload mocking.
Note: I tried to fix everything to Rack 1.5.2 except for the link to the Rack SPEC (so beware). Links to Ruby StdLib lead to the current version.
I have this configuration in the controller in Padrino
MyProject::App.controllers do
get '/' do
handlebars :index
end
get :file, :with => :tokenId do
tokenId = params[:tokenId]
[extra logic]
end
end
GET / works.
GET /file/abc doesn't.
GET /file/:tokenId works!
It looks like :token is not recognized as a parameter placeholder in the route definition.
I've tried
get "/file/:tokenId"
too but with no luck.
I can't find any information on any similar issue, anybody can help? Happy to add more information if needed.
Okay so I am unsure why the change made a difference but camelCase is generally considered poor syntax for variables in ruby.(Padrino may be calling a method such as underscore on your variable i.e.
"tokenID".underscore.to_sym
#=>:token_id
Using underscored_variables instead. (e.g. :tokenID becomes :token_id. This structure also allows for interacting with databases in a nicer way as well since your columns will have names such as token_id not tokenID.
There are uses for camelCasing in ruby and rails such as class naming and generators but trying keep all local and instance variables in lowercase underscore format.
I don't do much work in padrino so I am not 100% sure why this change helped but I am glad I could help.
I have been looking at Padrino for a project I am working on, and it seems a great fit, as I would ideally be wanting to support data being sent and received as json.
However I am wondering if there is any automated helper or functionality built in to take data from a post request (or other request) and put that data into the model without having to write custom logic for each model to process the data?
In the Blog example they briefly skim over this but just seem to pass the parameter data into the initilizer of their Post model, making me assume that it just magically knows what to do with everything... Not sure if this is the case, and if so is it Padrino functionality or ActiveRecord (as thats what they seem to use in the example).
I know I can use ActiveSupport for JSON based encoding/decoding but this just gives me a raw object, and as the storage concerns for each model reside within the main model class I would need to use a mixin or something to achieve this, which seems nasty.
Are there any good patterns/functionality around doing this already?
Yep, you can use provides and each response object will call to_json i.e:
get :action, :provides => :json do
#colletion = MyCollection.all
render #collection # will call #collection.to_json
end
Here an example of an ugly code that fills certain models.
# Gemfile
gem 'json' # note that there are better and faster gems like yajl
# controller
post "/update/:model/:id", :provides => :json do
if %w(Account Post Category).include?(params[:model])
klass = params[:model].constantize
klass.find(params[:id])
klass.update_attributes(JSON.parse(params[:attributes]))
end
end
Finally if you POST a request like:
attributes = { :name => "Foo", :category_id => 2 }.to_json
http://localhost:3000/Account/12?attributes=#{attributes}
You'll be able to update record 12 of the Account Model.
I want users to be able to enter a url and then put a link to that url in my view.
Valid inputs could be e.x. https://www.google.com/path, http://www.google.com, www.google.com
Is there are standard rails way to 1) validate that input is a valid url format and 2) convert that third format to http://www.google.com in my views so the external link works?
I don't want to re-invent the wheel if I can avoid it.
Check this out:
validates_format_of :website, :with => URI::regexp(%w(http https))
Source: http://intridea.com/2009/2/18/quick-tip-url-validation-in-rails?blog=company
To format a URL that is missing the protocol (http or https), I would do a before_save hook that prepends it if it's missing:
before_save :format_url
...
def format_url
self.website = "http://#{self.website}" unless self.website[/^https?/]
end
The Domainatrix gem comes highly recommended for validating URLs:
https://github.com/pauldix/domainatrix
I want use riak with my sinatra application.
I'm using gem ripple, describe simple model and simple form for store data.
Then I want to show all saved entries, using "Article.all" all good, but when i store new entry and refresh page - list of entryies not updates until I restart my application.
I'm trying irb, trying sinatra\reloader, but nothing...
Then, I post new entry, it's momentaly appear in default riak rest interface, and when use riack-client directly all good.
require 'ripple'
require 'sinatra'
class Article
include Ripple::Document
property :title, String
property :body, String
end
get '/' do
#articles = Article.all
erb :articles
end
post '/' do
article = Article.new(:title => params[:title], :body => params[:body])
article.save
end
All is a costly operation in Riak and does not work. If u use the latest version of the Gem for github you will get a error stating the same.