Skip to content

Commit 6c88536

Browse files
committed
closes #351 and #403
1 parent 8c17e11 commit 6c88536

6 files changed

Lines changed: 92 additions & 11 deletions

File tree

docs/hyper-state/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ class DisplaySquare
348348
.on(:click) { Game.handle_click(id) }
349349
end
350350
end
351+
351352
class DisplayBoard < HyperComponent
352353
render(DIV) do
353354
(0..6).step(3) do |row|
@@ -503,5 +504,5 @@ a component **unless** the state will be accessed outside the component. Howev
503504
would be better off to move the state into a separate store.
504505

505506
> In addition components also act as the **Observers** in the system. What this means is
506-
that current component that is running its render method is recording all stores that call `observe`, when
507+
that the current component that is running its render method is recording all stores that call `observe`, when
507508
a store mutates, then all the components that recorded observations will be rerendered.

ruby/hyper-model/lib/active_record_base.rb

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,19 +129,31 @@ def finder_method(name, &block)
129129
end
130130
end
131131

132+
def allow_remote_access_to(*methods, &block)
133+
methods = methods.collect { |meth| meth.is_a?(Hash) ? meth.keys : meth }.flatten
134+
methods.each do |name|
135+
define_method("__secure_remote_access_to_#{name}") do |_self, acting_user, *args|
136+
begin
137+
old = self.acting_user
138+
self.acting_user = acting_user
139+
allowed = !block || instance_eval(&block) rescue nil
140+
return send(name, *args) if allowed
141+
142+
Hyperstack::InternalPolicy.raise_operation_access_violation(
143+
:illegal_remote_access, "Access denied to #{name}"
144+
)
145+
ensure
146+
self.acting_user = old
147+
end
148+
end
149+
end
150+
end
151+
132152
def server_method(name, _opts = {}, &block)
133153
# callable from the server internally
134154
define_method(name, &block)
135155
# callable remotely from the client
136-
define_method("__secure_remote_access_to_#{name}") do |_self, acting_user, *args|
137-
begin
138-
old = self.acting_user
139-
self.acting_user = acting_user
140-
send(name, *args)
141-
ensure
142-
self.acting_user = old
143-
end
144-
end
156+
allow_remote_access_to(name)
145157
end
146158

147159
# relationships (and scopes) are regulated using a tri-state system. Each

ruby/hyper-model/lib/reactive_record/active_record/class_methods.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,18 @@ def server_method(name, default: nil)
364364
end
365365
end
366366

367+
def allow_remote_access_to(*methods)
368+
methods.each do |meth|
369+
if meth.is_a? Hash
370+
puts "defining these guys: #{meth}"
371+
meth.each { |name, default| server_method(name, default: default) }
372+
else
373+
puts "defining this guy: #{meth}"
374+
server_method(meth)
375+
end
376+
end
377+
end
378+
367379
# define all the methods for each column. To allow overriding the methods they will NOT
368380
# be defined if already defined (i.e. by the model) See the instance_methods module for how
369381
# super calls are handled in this case. The _hyperstack_internal_setter_... methods

ruby/hyper-model/spec/batch6/server_method_spec.rb renamed to ruby/hyper-model/spec/batch1/misc/server_method_spec.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,42 @@ class ServerMethodTester < HyperComponent
8888
expect(TestModel.count).to be_zero
8989
expect(ChildModel.count).to be_zero
9090
end
91+
92+
it "will allow remote access to methods" do
93+
TodoItem.class_eval do
94+
def foo
95+
"foo"
96+
end
97+
98+
def bar
99+
"bar"
100+
end
101+
102+
def broken
103+
"broken"
104+
end
105+
106+
def defaulted
107+
"defaulted"
108+
end
109+
end
110+
isomorphic do
111+
TodoItem.class_eval do
112+
allow_remote_access_to(:foo, :bar) { acting_user.nil? }
113+
allow_remote_access_to(:broken) { acting_user.admin? }
114+
allow_remote_access_to(:dontcallme, defaulted: "loading") { true }
115+
end
116+
end
117+
client_option raise_on_js_errors: :off
118+
expect { TodoItem.last.foo }.on_client_to be_nil
119+
expect { Hyperstack::Model.load { TodoItem.last.foo } }.on_client_to eq("foo")
120+
expect { TodoItem.last.bar }.on_client_to be_nil
121+
expect { Hyperstack::Model.load { TodoItem.last.bar } }.on_client_to eq("bar")
122+
expect { Hyperstack::Model.load { TodoItem.last.broken } }.on_client_to be_nil
123+
expect { TodoItem.last.defaulted }.on_client_to eq "loading"
124+
expect { Hyperstack::Model.load { TodoItem.last.defaulted } }.on_client_to eq("defaulted")
125+
errors = page.driver.browser.manage.logs.get(:browser).select { |m| m.level == "SEVERE" }
126+
expect(errors.count).to eq(2)
127+
expect(errors.first.message).to match(/the server responded with a status of 403 \(Forbidden\)/)
128+
end
91129
end

ruby/hyper-spec/lib/hyper-spec/helpers.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ def before_mount(&block)
8282

8383
def isomorphic(&block)
8484
yield
85-
before_mount(&block)
85+
if page.instance_variable_get('@hyper_spec_mounted')
86+
internal_evaluate_ruby(&block)
87+
else
88+
before_mount(&block)
89+
end
8690
end
8791

8892
# Allows options to the mount method to be specified globally

ruby/hyper-spec/spec/hyper_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,20 @@ def factorial(n)
108108
expect(evaluate_ruby('factorial(5)')).to eq(factorial(5))
109109
end
110110

111+
it "can load isomorphic code after loading" do
112+
on_client do
113+
CONSTANT = 1
114+
end
115+
CONSTANT = 1
116+
isomorphic do
117+
def factorial(n)
118+
n==CONSTANT ? CONSTANT : n * factorial(n-CONSTANT)
119+
end
120+
nil
121+
end
122+
expect(evaluate_ruby('factorial(5)')).to eq(factorial(5))
123+
end
124+
111125
context 'promise helpers' do
112126
# just to demonstrate a few things:
113127
# 1 - You can use methods like mount, isomorphic, on_client in before(:each) blocks

0 commit comments

Comments
 (0)