Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 96 #195

Merged
merged 8 commits into from Sep 21, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions pakyow-presenter/lib/pakyow/presenter/base.rb
Expand Up @@ -2,6 +2,7 @@

require 'pakyow/presenter/view_store'
require 'pakyow/presenter/view'
require 'pakyow/presenter/form'
require 'pakyow/presenter/template'
require 'pakyow/presenter/page'
require 'pakyow/presenter/container'
Expand Down
64 changes: 64 additions & 0 deletions pakyow-presenter/lib/pakyow/presenter/form.rb
@@ -0,0 +1,64 @@
module Pakyow
module Presenter
class Form
attr_reader :view, :context

PATCH_METHOD_INPUT = <<-HTML
<input type="hidden" name="_method" value="patch">
HTML

def initialize(view, context)
@view = view
@context = context
end

def create(*binding_args, &block)
bind_form_action(binding_args, block) do |view|
view.attrs.action = routes.path(:create, request_params) if routes
end
end

def update(*binding_args, &block)
bind_form_action(binding_args, block) do |view|
if routes
route_params = request_params.merge(
:"#{scoped_as}_id" => view.attrs.__send__('data-id').value
)

view.attrs.action = routes.path(:update, route_params)
end

view.prepend(View.new(PATCH_METHOD_INPUT))
end
end

private

def bind_form_action(binding_args, block)
data = binding_args.first

view.bind(binding_args) { |view, _| yield(view) }

return if block.nil?

if block.arity == 1
view.instance_exec(data, &block)
else
block.call(view, data)
end
end

def routes
@routes ||= Router.instance.group(scoped_as)
end

def scoped_as
view.scoped_as
end

def request_params
context.request.params
end
end
end
end
5 changes: 5 additions & 0 deletions pakyow-presenter/lib/pakyow/presenter/view_context.rb
Expand Up @@ -59,6 +59,11 @@ def subject
end
end

def form(*scope_args)
view = scope(*scope_args).subject
Form.new(view, context)
end

# Pass these through, handling the return value.
#
def method_missing(method, *args, &block)
Expand Down
Expand Up @@ -14,6 +14,64 @@
D
}

let(:router) { Pakyow::Router.instance }
let(:group) { Pakyow::Router.instance.group(:foo) }
let(:request) { mock_request }
let(:app_context) { Pakyow::AppContext.new(request, nil) }
let(:view_context) { Pakyow::Presenter::ViewContext.new(view, app_context) }

context 'when creating a form' do
it 'sets the action' do
expect(request).to receive(:params) { {} }
expect(group).to receive(:path) { '/foo' }.with(:create, {})
expect(router).to receive(:group) { group }.with(:foo)

view_context.form(:foo).create({})
expect(view.scope(:foo).first.instance_variable_get(:@doc).to_s).to include %(action="/foo")
end

context 'with a block' do
before :each do
expect(group).to receive(:path) { '/foo' }.with(:create, {})
expect(router).to receive(:group) { group }.with(:foo)
end

context 'with one argument' do
it 'evaluates the block in the view context and passes the data' do
block = lambda { |data| prop(:named) }
form = view_context.form(:foo)

expect(form.view).to receive(:prop)
form.create({}, &block)
end
end

context 'with more than one argument' do
it 'calls the block with the view and data' do
block = lambda { |view, data| @view, @data = view, data }
form = view_context.form(:foo)
form.create({}, &block)

expect(@view).to eq form.view
expect(@data).to eq({})
end
end
end
end

context 'when updating a form' do
it 'sets the _method and action' do
expect(request).to receive(:params) { { other: 'param' } }
expect(group).to receive(:path) { '/foo/1' }.with(:update, foo_id: 1, other: 'param')
expect(router).to receive(:group) { group }.with(:foo)

view_context.form(:foo).update(id: 1)
html = view.scope(:foo).first.instance_variable_get(:@doc).to_s
expect(html).to include %(name="_method" value="patch")
expect(html).to include %(action="/foo/1")
end
end

context 'when binding to unnamed field' do
it 'sets name attr' do
view.scope(:foo).bind(unnamed: 'test')
Expand Down