Skip to content

Commit fca7d6d

Browse files
committed
Merged cookies from mrplum.
2 parents 583c4e2 + fc72e66 commit fca7d6d

File tree

6 files changed

+153
-1
lines changed

6 files changed

+153
-1
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ tmtags
1717
## VIM
1818
*.swp
1919

20+
## RUBYMINE
21+
.idea
22+
2023
## PROJECT::GENERAL
2124
coverage
2225
doc

README.markdown

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,36 @@ class API < Grape::API
149149
end
150150
````
151151

152+
## Cookies
153+
154+
You can set, get and delete your cookies very simply using `cookies` method:
155+
156+
````ruby
157+
class API < Grape::API
158+
get '/counter' do
159+
cookies[:counter] ||= 0
160+
cookies[:counter] += 1
161+
{ :counter => cookies[:counter] }
162+
end
163+
164+
delete '/counter' do
165+
{ :result => cookies.delete(:counter) }
166+
end
167+
end
168+
````
169+
170+
To set more than value use hash-based syntax:
171+
172+
````ruby
173+
cookies[:counter] = {
174+
:value => 0,
175+
:expires => Time.tomorrow,
176+
:domain => '.example.com',
177+
:path => '/'
178+
}
179+
cookies[:counter][:value] +=1
180+
````
181+
152182
## Raising Errors
153183

154184
You can raise errors explicitly.

lib/grape.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module Grape
88
autoload :Client, 'grape/client'
99
autoload :Route, 'grape/route'
1010
autoload :Entity, 'grape/entity'
11+
autoload :Cookies, 'grape/cookies'
1112

1213
module Middleware
1314
autoload :Base, 'grape/middleware/base'

lib/grape/cookies.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
module Grape
2+
class Cookies
3+
4+
def initialize
5+
@cookies = {}
6+
@send_cookies = {}
7+
end
8+
9+
def read(request)
10+
request.cookies.each do |name, value|
11+
@cookies[name.to_sym] = value
12+
end
13+
end
14+
15+
def write(header)
16+
@cookies.select { |key, value|
17+
@send_cookies[key.to_sym] == true
18+
}.each { |name, value|
19+
Rack::Utils.set_cookie_header!(
20+
header, name, value.instance_of?(Hash) ? value : { :value => value })
21+
}
22+
end
23+
24+
def [](name)
25+
@cookies[name]
26+
end
27+
28+
def []=(name, value)
29+
@cookies[name.to_sym] = value
30+
@send_cookies[name.to_sym] = true
31+
end
32+
33+
def each(&block)
34+
@cookies.each(&block)
35+
end
36+
37+
def delete(name)
38+
self.[]=(name, { :value => 'deleted', :expires => Time.at(0) })
39+
end
40+
end
41+
end

lib/grape/endpoint.rb

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,18 @@ def header(key = nil, val = nil)
157157
end
158158
end
159159

160+
# Set or get a cookie
161+
#
162+
# @example
163+
# cookies[:mycookie] = 'mycookie val'
164+
# cookies['mycookie-string'] = 'mycookie string val'
165+
# cookies[:more] = { :value => '123', :expires => Time.at(0) }
166+
# cookies.delete :more
167+
#
168+
def cookies
169+
@cookies ||= Cookies.new
170+
end
171+
160172
# Allows you to define the response body as something other than the
161173
# return value.
162174
#
@@ -231,10 +243,12 @@ def run(env)
231243
@request = Rack::Request.new(@env)
232244

233245
self.extend helpers
246+
cookies.read(@request)
234247
run_filters befores
235248
response_text = instance_eval &self.block
236249
run_filters afters
237-
250+
cookies.write(header)
251+
238252
[status, header, [body || response_text]]
239253
end
240254

spec/grape/endpoint_spec.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,69 @@ def app; subject end
4545
end
4646
end
4747

48+
describe '#cookies' do
49+
it 'should be callable from within a block' do
50+
subject.get('/get/cookies') do
51+
cookies['my-awesome-cookie1'] = 'is cool'
52+
cookies['my-awesome-cookie2'] = {
53+
:value => 'is cool too',
54+
:domain => 'my.example.com',
55+
:path => '/',
56+
:secure => true,
57+
}
58+
cookies[:cookie3] = 'symbol'
59+
cookies['cookie4'] = 'secret code here'
60+
end
61+
62+
get('/get/cookies')
63+
64+
last_response.headers['Set-Cookie'].tap { |set_cookies|
65+
set_cookies.should =~ /my-awesome-cookie1=is\+cool\n/
66+
set_cookies.should =~ /my-awesome-cookie2=is\+cool\+too;\ domain=my\.example\.com;\ path=\/;\ secure\n/
67+
set_cookies.should =~ /cookie3=symbol\n/
68+
set_cookies.should =~ /cookie4=secret\+code\+here/
69+
}
70+
end
71+
72+
it "should set browser cookies and should not set response cookies" do
73+
subject.get('/username') do
74+
cookies[:username]
75+
end
76+
get('/username', {}, 'HTTP_COOKIE' => 'username=mrplum; sandbox=true')
77+
78+
last_response.body.should == 'mrplum'
79+
last_response.headers['Set-Cookie'].should_not =~ /username=mrplum/
80+
last_response.headers['Set-Cookie'].should_not =~ /sandbox=true/
81+
end
82+
83+
it "should set and update browser cookies" do
84+
subject.get('/username') do
85+
cookies[:sandbox] = true if cookies[:sandbox] == 'false'
86+
cookies[:username] += "_test"
87+
end
88+
get('/username', {}, 'HTTP_COOKIE' => 'username=user; sandbox=false')
89+
last_response.body.should == 'user_test'
90+
last_response.headers['Set-Cookie'].should =~ /username=user_test/
91+
last_response.headers['Set-Cookie'].should =~ /sandbox=true/
92+
end
93+
94+
it "should delete cookie" do
95+
subject.get('/test') do
96+
sum = 0
97+
cookies.each do |name, val|
98+
sum += val.to_i
99+
cookies.delete name
100+
end
101+
sum
102+
end
103+
get('/test', {}, 'HTTP_COOKIE' => 'delete_this_cookie=1; and_this=2')
104+
last_response.body.should == '3'
105+
last_response.headers['Set-Cookie'].should ==
106+
"delete_this_cookie=deleted; expires=Thu, 01-Jan-1970 00:00:00 GMT\n" +
107+
'and_this=deleted; expires=Thu, 01-Jan-1970 00:00:00 GMT'
108+
end
109+
end
110+
48111
describe '#params' do
49112
it 'should be available to the caller' do
50113
subject.get('/hey') do

0 commit comments

Comments
 (0)