My “spare-time” project is to make a Silverlight plugin for Rails, which allows your controller/view code to either run on the server or the client. It's not available yet, but if you want it faster maybe making a big stink about it to my boss would work. Here's a messy contrived example of what you could do with it, but it makes the point.
end
If someone visited /foo, it would show them a link saying “Show time”. The line that makes all the difference is client :time, so ...
- Without client :time
- link_to_remote call would generate a javascript Ajax.Request(‘/foo/time’)
- time would be run on the server
- render :update block would generate javascript to add the “server-generated” time to the bottom on the time div, and then be send back to the client to be run.
- With client :time
- a copy of this controller would be sent to the client when someone visits /foo.
- link_to_remote call would use Silverlight to call the time action on the client
- render :update block would execute just as it says, without needing to generate javascript.
The beauty of this is with one line you’ve decided to run a bunch of server-side code on the client, and it just happens for you.
This is better than sliced bread!The Rails way of doing AJAX is by generating HTML on the sever and sending it back to the client with JavaScript that knows how to insert the HTML into the page. This is an awesome way to do it, but can be pretty heavy-weight if you're schlepping around a lot of HTML. In those cases it doesn't save much “response size” over just sending the whole page back again.
People overcome this by pushing some logic to the client. However, this leads to duplicate their Rails logic in JavaScript, and handle serializing/deserializing their ActiveRecord object by hand. This is just flat-out painful, and by the end of it you realize all this server-side Rails code you wrote is wasted.
This pattern of pushing server-side logic to the client is the approach big sites like Twitter and GMail have taken, and it’s really the best way to make web applications feel more responsive ... it’s the whole RIA thing and why Silverlight is cool. Twitter went through a ton of growing pain getting their app to scale well, and I can bet much of it was attributed to “what should we do on the client, and what should we do on the server” (and what should be cached and what should be stored in a database, but that's a different topic altogether).
I’d like to live in a world where you can write your entire app in Ruby, and not have to throw away a ton of code to get some of it running on the client. That’s what I’m trying to accomplish with this project.
You're right, this is better than slided bread!:-) Let me know what you think about this, and I'll get some code into your hands soon.
As you can probably tell, this personally hit me hard. We had this problem with Assistment. The tutor just wasn’t scaling, and we decided to port the whole thing to JavaScript, eagerly load data onto the client, etc ... all the things we expected our web framework to do for us. This pissed me off to no end, and Ruby in Silverlight is a way to undo those wrongs and make all this possible.Update: By the way, I got this example working today! Without "client :time" it works as usual, making an AJAX request when clicking on the "Show time" link. But when you add "client :time", clicking on "Show time" simply runs the code on the client! Awesome!
I'm probably going to put this up on RubyForge ... just not sure whether I should make my own project or stick it in the IronRuby? Regardless, code is coming =)

7 comments:
Wow this looks great.
The "link_to_remote" thing seems a bit awkward since it's being run on the client, though. The "link_to_function" method would be more natural, since it's a local function, or better yet: "link_to_silverlight_function"
The client call at the beginning seems really clean. Does it send the whole controller to the client, then? That wasn't completely clear.
The rational behind using link_to_remote is because I want the code to work regardless of whether "client :time" is there or not. Idea being you write you app without this client/server division in mind, but not have to rewrite any code when you do make the "client or server" decision.
I wouldn't overload link_to_function when it takes a string, since code today depends on that being JavaScript. However, when it takes a block I could run it with Silverlight if available.
I'd definitely have link_to_silverlight_function, but its existence is unrelated to running controller code on the client. Granted, very useful though, as it's a much more explicit way to run code in Silverlight (and probably the lower hanging fruit =P).
By the way, I got this example working today! Without "client :time" it works as usual, making an AJAX request when clicking on the "Show time" link. But when you add "client :time", clicking on "Show time" simply runs the code on the client! Awesome!
I'm probably going to put this up on RubyForge ... just not sure whether I should make my own project or stick it in the IronRuby? Regardless, code is coming =)
Oh, and to answer you last question Josh:
"a copy of this controller would be sent to the client when someone visits /foo."
So today the entire controller is sent to the client. In the future, I'll also send down the views for all client actions as well (once I get erb working).
It'll be interesting to see if I can keep this "figuring out all the dependencies" game going =)
That is pretty sweet, you should generalize it a bit though so you don't HAVE to use silverlight, be interesting to see what other hosts could be used. Moonlight for instance. Very, very cool though.
congratulations on getting it working!
I really like the idea of sending the views as well.
Are the controllers sent all at once, or is it on by request basis? For example, someone requests /users/list
and the entire users controller gets sent down, along with all the view associated with that controller, or are they all sent in the initial request?
@michael: Well, if I give the code out today it will only work with Silverlight. =) Once Moonlight gets up to snuff then it'll just work in that as well. Though, the only requirement for a host is that it runs real Ruby in the browser; Silverlight is the only thing that does that today.
@josh: Gotta have views on the client if you're gonna run real controller code. =)
My thinking about "when do controllers go to the client" is whenever they're needed. Though, this is going to be hard, because for any rendered action, you need to see if there are any "links" to client actions. If so, the controller that action is in, plus any dependencies it may have on other controllers/modules/views, needs to be sent to the client. The hard part is all these dependencies are dynamic (for instance, if you say "User" and it's not defined already, Rails will require /app/models/User.rb for you). Realistically, I may just send the controller, all the models, all the libs, and the actions views.
Another gotcha is "what if a client action calls another client action?" =) So, it's not such an easy problem, and I'm not gonna solve by speculating ... I'll just have to make it and go from there.
Post a Comment