Local variables in a block that are not passed as parameters [duplicate] - ruby

This question already has answers here:
Rails params explained?
(5 answers)
Closed 9 years ago.
I'm trying to understand how to make a variable available to a block that is not passed to the block as a parameter.
For example, how does Sinatra make params hash available?
get '/hello/:name' do
howAmIAccessingThis = params[:name]
end
Where is params coming from? This:
get '/hello/:name' do |params|
#hisName = params[:name]
end
might make sense because params is declared as a block argument, but that's not how it works. Looking through the source I cannot find how the params hash is getting passed to the block without it being a block parameter.

If it is not a local variable or a block variable, then it is a method. I don't know about Sinatra, but there must be a method params defined somewhere.

Using Parameters
Parameters in Sinatra are like everything else--simple and straightforward.
#!/usr/bin/env ruby
require 'rubygems'
require 'sinatra'
get '/hello/:name' do
"Hello #{params[:name]}!"
end
Once you've made this change, you'll need to restart the Sinatra application. Kill it with Ctrl-C and run it again. (There's a way around this, but we'll look at that in a future article.) Now, the parameters are straightforward. We've made an action called /hello/:name. This syntax is imitating what the URLs will look like, so go to http://localhost:4567/hello/Your Name to see it in action.
The /hello portion matches that portion of the URL from the request you made, and :name will absorb any other text you give it and put it in the params hash under the key :name. Parameters are just that easy. There is of course much more you can do with these, including regexp-based parameters, but this is all you'll need in almost every case.
Reference: http://ruby.about.com/od/sinatra/a/sinatra2.htm
EDIT
params values can come from the query string of a GET request, or the form data of a POST request, but there's also a third place they can come from: The path of the URL.
As you might know, Rails uses something called routes to direct requests to their corresponding controller actions. These routes may contain segments that are extracted from the URL and put into params. For example, if you have a route like this:
match 'products/:id', ...
Then a request to a URL like http://example.com/products/42 will set params[:id] to 42
So, whenever an URL GET, POST or Path contains such pattern then params hash is automatically constructed by rails.
Also check the Parameters section(Section 4) here

Related

Ruby on Sinatra: Imitate a request based on a parameter

I am currently developing a Ruby API based on Sinatra. This API mostly receives GET requests from an existing social platform which supports external API integration.
The social platform fires off GET requests in the following format (only relevant parameters shown):
GET /{command}
Parameters: command and text
Where text is a string that the user has entered.
In my case, params[:text] is in fact a series of commands, delimited by a space. What I want to achieve is, for example: If params[:text]="corporate finance"
Then I want my API to interpret the request as a GET request to
/{command}/corporate/finance
instead of requesting /{command} with a string as a parameter containing the rest of the request.
Can this be achieved on my side? Nothing can be changed in terms of the initial request from the social platform.
EDIT: I think a better way of explaining what I am trying to achieve is the following:
GET /list?text=corporate finance
Should hit the same endpoint/route as
GET /list/corporate/finance
This must not affect the initial GET request from the social platform as it expects a response containing text to display to the user. Is there a neat, best practice way of doing this?
get "/" do {
text = params[:text].split.join "/"
redirect "#{params[:command]}/#{text}"
end
might do the trick. Didn't check though.
EDIT: ok, the before filter was stupid. Basically you could also route to "/" and then redirect. Or, even better:
get "/:command" do {
text = params[:text].split.join "/"
redirect "#{params[:command]}/#{text}"
}
There a many possible ways of achieving this. You should check the routes section of the sinatra docs (https://github.com/sinatra/sinatra)
The answer by three should do the trick, and to get around the fact that the filter will be invoked with every request, a conditional like this should do:
before do
if params[:text]
sub_commands = params[:text].split.join "/"
redirect "#{params[:command]}/#{sub_commands}"
end
end
I have tested it in a demo application and it seems to work fine.
The solution was to use the call! method.
I used a regular expression to intercept calls which match /something with no further parameters (i.e. /something/something else). I think this step can be done more elegantly.
From there, I split up my commands:
get %r{^\/\w+$} do
params[:text] ? sub_commands="/"+params[:text].split.join("/") : sub_commands=""
status, headers, body = call! env.merge("PATH_INFO" => "/#{params[:command]}#{sub_commands}")
[status, headers, body]
end
This achieves exactly what I needed, as it activates the correct endpoint, as if the URL was typed it the usual format i.e. /command/subcommand1/subcommand2 etc.
Sorry, I completely misunderstood your question, so I replace my answer with this:
require 'sinatra'
get '/list/?*' do
"yep"
end
like this, the following routes all lead to the same
You need to add a routine for each command or replace the command with a * and depend your output based on a case when.
The params entered by the user can be referred by the params hash.
http://localhost:4567/list
http://localhost:4567/list/corporate/finance
http://localhost:4567/list?text=corporate/finance

Ruby WebMock: Getting Actual Parameters Passed Through a Method and Using Them in Spec File

I'm using WebMock to stub out HTTP requests. I have this one particular call where, instead of creating dummy data to pass through, I want to be able to capture the actual parameters I would pass into my send() method. Therefore, I need access to those actual parameters in my spec and I imagine I would need to somehow capture that context.
So, for example, in my application I'm calling this method:
send(method, uri, :body => data_file)
And in my spec file I'm stubbing the method:
FoobarModule.should_receive(:send).with(args)
Is there any way I could -- in WebMock, Rspec -- get the context of when send() is being called in the application and grab those parameters I'm passing through to use them within the spec and replace them with args?
I've looked through the documentation and I don't see much of anything on this. If there's anyone aware of this, I would greatly appreciate your help. Thanks.
Using WebMock you could use request callbacks to capture request data:
WebMock.allow_net_connect!
WebMock.after_request do |request_signature, response|
puts request_signature
end

Sinatra and question mark

I need to make some methods with Sinatra that should look like:
http//:localhost:1234/add?string_to_add
But when I declare it like this:
get "/add?:string_to_add" do
...
end
it doesn't see the string_to_add param.
How should I declare my method and use this parameter to make things work?
In a URL, a question mark separates the path part from the query part. The query part normally consists of name/value pairs, and is often constructed by a web browser to match the data a user has entered into a form. For example a url might look like:
http://example.com/submit?name=John&age=93
Here the path section in /submit, and the query sections is name=John&age=93 which refers to the value “John” for the name key, and “93” for the age.
When you create a route in Sinatra, you only specify the path part. Sinatra then parses the query, and makes the data in it available in the params object. In this example you could do something like this:
get '/submit' do
name = params[:name]
age = params[:age]
# use name and age variables
...
end
If you use a ? character when defining a Sinatra route, it makes part of the url optional. In the example you used (get "/add?:string_to_add"), it will actually match any url starting with /ad, then optionally another d, and then anything else will be put in the :string_to_add key of the params hash, and the query section will be parsed separately. In other words the question mark makes the preceding d character optional.
If you want to get the ‘raw’ text of the query string in Sinatra, you can use the query_string method of the request object. In your example that would look something like this:
get '/add' do
string_to_add = request.query_string
...
end
Note that the route doesn’t include the ? character, just the base /add.
You should declare it as:
get "/add?:string_to_add?" do
...
end

Sinatra/Rack params[] in before block

I'm making a site using Sinatra, everything is going well, or was until I needed to access the params[] hash in the before block.
Basically, I'm trying to do this:
before do
if params[:forum_id]
#forum = Forum.find(params[:forum_id])
build_breadcrumbs(#forum.parents)
# ... more code, snipped to keep it short
end
end
But the thing is, I can't call the params[] hash in the before block, does anyone have any ideas?
The reason I'm putting this code in the before block is because I'd rather not have to go and put it in every one of my get and post blocks for every page.
From the docs:
Before filters are evaluated before each request within the same
context as the routes will be and can modify the request and response.
Since this happens before the actual request, you can't access the request parameters. What you can do is put the repetitive code into a method and call that in your route blocks.
This is not true anymore. I just tested it. You can now access params in before {...}

Sinatra and computed view name

I'm completely new in Ruby and Sinatra so please forgive the trivial question:
I wanted to compute the view name instead of just passing in a symbol. I wanted the same action to return different views depending on the current state. There's like 20 different states so putting a good naming convention allows me to express the view name as a string very easily:
get "/page" do
erb "page-#{session[:page]}"
end
When I do that all I get is the string instead of the rendered view. Can anyone explain to me how I could do that in Sinatra?
I'd say you're probably looking for String#to_sym. I didn't test now, but all the examples say erb receives a symbol argument, not a string - so try this:
erb "page-#{session[:page]}".to_sym
or equivalently
erb :"page-#{session[:page]}"
If you pass string to erb it tries to render that string directly, not seeking for view with corresponding name. Converting string to symbol will help.

Resources