Staying RESTful and triggering actions without saving a record

the example i’m making uses state_machine because it’s part of my
current setup but this isnt a state_machine specific problem.

i have a model called Station. it’s an abstract concept for “an area
in which work is performed”… when i’m using the app the Stations
could be anything from “simulation terminal A” to “the lathe in
building C”…

each station has various properties (one of which is conveniently
“state”) and i would like to use buttons on my form (or links if it
can be done in an xss safe way) to immediately change one of those
properties… one button for example may be “release to floor” which
when clicked would - in a non restful app - call the “release” action
on the station controller. the release action would then take the
station and call “release!” on it… however i want to accomplish this
using standard actions.

just using a text box and “saving” the record doesn’t automatically
fire the state-changing events (which i think is a good thing) AND
that type of structure does not relate to my problem in a convenient
way… there’s a handful of cases where i just want to have a few
buttons peppered in my form that when clicked, perform a direct action
on my object without having to “invent” a bunch of non-standard
actions…

any tips?
thank you much,

  • FJM

Hey Frank,

state_machine actually provides support for executing events using a
standard REST interface. Rather than calling the event method
directly (such as “release!”), you can set an the machine’s event
attribute like so:

station.state_event = ‘release’
station.save!

Any event that gets set in “state_event” will be validated and fired
when the record is saved. There’s a full example (model, controller,
and views) of this here:

Hope this helps!

-Aaron

On May 17, 10:50 pm, “[email protected][email protected]

i suppose state_machine was a bad example to start with (but is my
current situation so it was unavoidable)…

the example you pointed me to involved changing a collection_select
and clicking the save button…

i want to instead display different buttons (or links) depending on a
users roles and allow a single click of those buttons to trigger
actions. any suggestions on how to do that?

thanks for the state_machine tip though - i didnt know about that
functionality and can see my self using it in other places.

  • FJM

i’ll try another example, maybe it’ll be a little clearer - also, ill
take SM out of the equation.

suppose theres a job edit page… the page has all the job attributes,
title, description… etc. but i dont want to change those. i want a
button somewhere in the form called “mark & dupe”… what those actions
do is irrelevant – BUT – i dont want to create a non-standard
action. what i want is to know how to make button_to send the form to
the update action with special parameters – in my controller i would
like to test for those special parameters and when encountered,
execute my mark and dupe methods.

does that make sense? maybe im trying to fit the wrong solution to the
problem but in my interface this seems like hte most appropriate
solution.

thanks again,

  • FJM

On 18 May 2010 17:06, [email protected] [email protected]
wrote:

i suppose state_machine was a bad example to start with (but is my
current situation so it was unavoidable)…

the example you pointed me to involved changing a collection_select
and clicking the save button…

i want to instead display different buttons (or links) depending on a
users roles and allow a single click of those buttons to trigger
actions. any suggestions on how to do that?

I am not sure I see the problem. A form can have multiple buttons if
you want all the buttons to go to the same action (the button name is
passed in the params), or you can use button_to if you want them to go
to different actions.

Perhaps I misunderstand the problem.

Colin

a form can only direct to one action though, correct?

i want these buttons to located inside of my form - and while ive
never tried it, i’ll assume that nesting forms leads to heartbreak and
homelessness…

if i have 20 different states… and am only going to need a user to
chose 1 of 3 at any given point in time, it doesnt make sense to have
20 separate actions… is there a way to pass put params in a button_to
or link_to? in my controllers update action, can i check if any
specific params are specified and then delegate to the appropriate
action? the docs for button_to don’t really help me too much.

[email protected] wrote:

i’ll try another example, maybe it’ll be a little clearer - also, ill
take SM out of the equation.

suppose theres a job edit page… the page has all the job attributes,
title, description… etc. but i dont want to change those. i want a
button somewhere in the form called “mark & dupe”… what those actions
do is irrelevant – BUT – i dont want to create a non-standard
action.
[…]

Why not? It’s honestly the most RESTful thing to do in your case, IMHO.

Likewise with state transitions: I don’t believe there’s anything wrong
or unRESTful with URLs like http://server/accounts/9/release .

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

[Please quote when replying, so that it is clear what you are responding
to.]

[email protected] wrote:

a form can only direct to one action though, correct?

Absent JavaScript, yes.

i want these buttons to located inside of my form - and while ive
never tried it, i’ll assume that nesting forms leads to heartbreak and
homelessness…

It leads to invalid HTML and unpredictable results.

But do these have to be submit buttons? Why not make them links?

if i have 20 different states… and am only going to need a user to
chose 1 of 3 at any given point in time, it doesnt make sense to have
20 separate actions…

Why the hell would you have 20 different states? Perhaps you’re abusing
your state machine…

But if not, then yeah, maybe a go_to_state action would work better.

is there a way to pass put params in a button_to
or link_to?

Sure, you can always have a query string in your URL, or play with your
routes to pass the appropriate parameters. Query strings work just as
well in Rails as anywhere else.

in my controllers update action, can i check if any
specific params are specified and then delegate to the appropriate
action?

Of course you can, though this will be messy if overdone.

the docs for button_to don’t really help me too much.

You probably don’t want button_to anyway – there’s generally no reason
to use JavaScript for something this simple.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

i want these buttons to located inside of my form - and while ive
never tried it, i’ll assume that nesting forms leads to …

It leads to invalid HTML and unpredictable results.

But do these have to be submit buttons? Why not make them links?

But a form can have multiple submit buttons; only the value of the one
clicked is passed as a parameter to your action…

FWIW,

Hassan S. ------------------------ [email protected]
twitter: @hassan

from what i’ve read - buttons are not the way to go… links are. now
with that in mind…

yes - the 20 states was a contrived example just to illustrate how
absurd it could become. and no matter what i do im sure time will show
me better ways to refactor… i just want to have a somewhat stable
starting point. more realistically is a model having 2 or 3 state
machines each having at most 4 or 5 states to track its status through
multiple parallel workflows.

so links are what i want - how do i make a link that is either post or
put and keeps me safe from xss or people just fooling with the urls?

ideally, i’d like my link to be formed as such
http://url.to.app/order/1?state1=newstate
or
http://url.to.app/order/1?takeownership (the controller will do
something like @order.owner = current_user? if params[:takeownership])

after i generate a link that looks like that, how do i get it to send
via put or post? which is the appropriate one?

thanks for the input and suggestions but i wont know the right way to
take this if i dont start somewhere that i feel is logical to my
problem - and then discovering the pros/cons from where im at - and
then moving forward…

  • FJM

so i can have a form submit to update, have the submit buttons have
different values and then in the update action figure out which one
was clicked? what is necessary beyond f.submit in my view?

thanks,

  • FJM

On May 18, 3:40 pm, Hassan S. [email protected]

On Tue, May 18, 2010 at 12:49 PM, [email protected]
[email protected] wrote:

so i can have a form submit to update, have the submit buttons have
different values and then in the update action figure out which one
was clicked?

Exactly.

what is necessary beyond f.submit in my view?

Just create multiple tags with different values, e.g.

<%= submit_tag ‘Accumulate’ %>
<%= submit_tag ‘Release’ %>
<%= submit_tag ‘Tenderize’ %> # etc…


Hassan S. ------------------------ [email protected]
twitter: @hassan

where can i find the documentation for all of the
action_controller_path functions?

multiple submits on a form are no longer a viable solution because the
only way to tell which one was hit was to know the name “value” of the
submit button… when its in different languages it gets ugly… im just
going to try to use a link_to solution but i cant figure out how _path
wants its arguments.

link_to ‘release’, station_path(@station, :state => :release), :method
=> :put

generates a url that looks right but doesnt work.

On May 18, 4:08 pm, Hassan S. [email protected]

[email protected] wrote:

where can i find the documentation for all of the
action_controller_path functions?

multiple submits on a form are no longer a viable solution because the
only way to tell which one was hit was to know the name “value” of the
submit button… when its in different languages it gets ugly… im just
going to try to use a link_to solution but i cant figure out how _path
wants its arguments.

link_to ‘release’, station_path(@station, :state => :release), :method
=> :put

generates a url that looks right but doesnt work.

You should probably read the Rails routing guide.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

yeah, i’ve read it half a dozen times - doesn’t give me any insight on
the argument list for the _path family of functions and apidock is
less than helpful as well.

searching through google led to some obscure blog that said i could
do:
link_to ‘do something’, station_path(@station, :station =>
{ :attribute => :value }), :method => :put

but why does this work and why aren’t the _path functions clearly
documented?

maybe someone who knows could point me to where these functions are
defined in the source tree (preferably in master)?

here’s what i ended up doing – if anyone can find a technical flaw
with it (like someone being able to trigger things just by messing
with urls) let me know. hopefully this helps someone else.

in my view i have

<% unless @machine.new_record? %>
<%= link_to ‘service’, machine_path(@machine, :event
=> :service), :method => :put %>
<%= link_to ‘release’, machine_path(@machine, :event
=> :release), :method => :put %>
<%= link_to ‘use’, machine_path(@machine, :event => :use), :method
=> :put %>
<% end %>

and in my controller (using rails 3 edge)

def update
@machine = Machine.find(params[:id])

if params[:event]
flash[:notice] = “an event was triggered.”

## do something with my @machine object here

respond_with @machine and return

end

flash[:notice] = “Machine successfully updated” if
@machine.update_attributes(params[:machine])

respond_with @machine
end

thanks for the input and advice - it was much appreciated,

  • FJM

[email protected] wrote:

yeah, i’ve read it half a dozen times

Read what? Please quote when replying so it’s clear what you’re
responding to.

  • doesn’t give me any insight on
    the argument list for the _path family of functions and apidock is
    less than helpful as well.

Are you talking about the routing guide?

In any case, the arguments are whatever is defined in that particular
route. Run rake routes or look at your routes file to see what that
would be.

searching through google led to some obscure blog that said i could
do:
link_to ‘do something’, station_path(@station, :station =>
{ :attribute => :value }), :method => :put

but why does this work and why aren’t the _path functions clearly
documented?

Because they’re generated from your routes, and so will be different for
each Rails app. This is pretty clearly explained in the routing guide,
as well as in the documentation for ActionController::Routing and
ActionController::Resources . Perhaps you should read those again.

maybe someone who knows could point me to where these functions are
defined in the source tree (preferably in master)?

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On May 19, 11:29 am, Marnen Laibow-Koser [email protected] wrote:

[email protected] wrote:

yeah, i’ve read it half a dozen times

Read what? Please quote when replying so it’s clear what you’re
responding to.

I have read the rails routing guide a dozen times.

  • doesn’t give me any insight on
    the argument list for the _path family of functions and apidock is
    less than helpful as well.

Are you talking about the routing guide?

Yes.

In any case, the arguments are whatever is defined in that particular
route. Run rake routes or look at your routes file to see what that
would be.

That doesn’t make any sense. My output of rake routes does not show a
function name for put requests. What I’ve discovered
(through trial and error) is that when using a _path function the
arguments can either be in the form of

_path(:id => @station)
_path(@station)
_path(@station, :attribute_not_on_the_model => :value)
_path(@station, :station => { :this_attribute_is_on_model => :value})

where in the guide is that explained? if it’s even in there it most
certainly is not clear unless you already have a very good grasp of
the subject. I don’t believe that it’s “typical” for someone reading
the guides (mostly beginners I’ll assume) to want to pass params in
their links and send them off as put requests.

as well as in the documentation for ActionController::Routing and
ActionController::Resources . Perhaps you should read those again.

ActionController::Resources is the only one of those that even hints
at the proper form for the _path functions and that’s only in the very
first example which doesn’t even say that it can be used for those
functions - it only says “this is what a so-and-so request looks
like”.
http://rails.rubyonrails.org/classes/ActionController/Resources.html

to quote the docs a little further down it says:
Named Route Helper
message message_url(id), hash_for_message_url(id),
message_path(id), hash_for_message_path(id)

that would lead me to believe that the only argument available to
those functions is id…

maybe someone who knows could point me to where these functions are
defined in the source tree (preferably in master)?

This is all I’m really interested in now. Simply for curiosities
sake… The rest I’ve figured out and is all moot.

In any case, the arguments are whatever is defined in that particular
route. Run rake routes or look at your routes file to see what that
would be.

That doesn’t make any sense.

Whether it makes sense or not, it is the case. :slight_smile: The arguments are the
:parameters in the route.

But I’ve never explicitly defined any parameters - and the notion of
the arguments simply being a params-like hash had never occurred to
me. I never saw it done.

My output of rake routes does not show a
function name for put requests.

No, but if you’re using map.resources, the paths for PUT requests are
the same as for named GET requests.

also a point that was not being connected in my head.

Using a link to a PUT request, though, is extremely smelly. Links
should practically always be GET.

not that i would do something so “ugly” as set a links appearance to
button - but does that make it any more acceptable? I’ve read plenty
of religious war associated with this concept and believe that it’s
best evaluated on a need by need basis. In the workflow of my
application a link that is styled a certain way most certainly conveys
to the user that it “does something important”. With xss protection in
rails and good testing it should be perfectly safe.

There’s also the stuff about named routes in ActionController::Routing.

Again, it depends on how your routes are defined.

That sentence should be added to the docs somewhere.

maybe someone who knows could point me to where these functions are
defined in the source tree (preferably in master)?

This is all I’m really interested in now. Simply for curiosities
sake… The rest I’ve figured out and is all moot.

I suspect looking at the source for the resources function would be a
good place to start.

Thank you kindly for the tip in that direction.

[email protected] wrote:
[…]

In any case, the arguments are whatever is defined in that particular
route. �Run rake routes or look at your routes file to see what that
would be.

That doesn’t make any sense.

Whether it makes sense or not, it is the case. :slight_smile: The arguments are the
:parameters in the route.

My output of rake routes does not show a
function name for put requests.

No, but if you’re using map.resources, the paths for PUT requests are
the same as for named GET requests.

Using a link to a PUT request, though, is extremely smelly. Links
should practically always be GET.

[…]

as well as in the documentation for ActionController::Routing and
ActionController::Resources . �Perhaps you should read those again.

ActionController::Resources is the only one of those that even hints
at the proper form for the _path functions and that’s only in the very
first example which doesn’t even say that it can be used for those
functions - it only says “this is what a so-and-so request looks
like”.
http://rails.rubyonrails.org/classes/ActionController/Resources.html

There’s also the stuff about named routes in ActionController::Routing.

to quote the docs a little further down it says:
Named Route Helper
message message_url(id), hash_for_message_url(id),
message_path(id), hash_for_message_path(id)

that would lead me to believe that the only argument available to
those functions is id…

Again, it depends on how your routes are defined.

maybe someone who knows could point me to where these functions are
defined in the source tree (preferably in master)?

This is all I’m really interested in now. Simply for curiosities
sake… The rest I’ve figured out and is all moot.

I suspect looking at the source for the resources function would be a
good place to start.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]