-
MIKE MOORE: Hello. My name is Mike Moore,
-
and I'm gonna talk about real-time Rails with
Sync.
-
So, hi. Hello. How's Rails Conf?
-
My name is Mike Moore. You might know be
-
as blowmage or blowmage depending on how you
want
-
to pronounce it. It doesn't matter.
-
I am very happy to be here. I'm leaving
-
in about an hour to fly home, so I'm
-
only here for this. And I'm a hundred percent,
-
totally prepared for this. I was not up all
-
night. I did not make these slides twenty
minutes
-
ago. Yeah.
-
So. Who likes live coding? Three people! All
right.
-
K. We're gonna talk about Sync. Sync is a
-
fantastic little Rails engine written by Chris
McCord. Is
-
Chris, where's Chris? Is he here? There he
is.
-
If you don't like it - that guy right
-
there. You can find it on the GitHub. That's
-
at chrismccord slash sync.
-
So yeah. Let's do this.
-
All right. So I have a. I have an
-
app. And I'm just gonna load it up here.
-
And it's a very simple app. I was gonna
-
have a little bit more interesting app to
demonstrate
-
this, but I ran into an issue. And maybe
-
we'll talk about that at the end. If we
-
have time.
-
But this is a very simple bloggish type of
-
application, where we've got posts, we've
got comments, we've
-
got users, and some tags. Oh, and also, this
-
is the git repo for Sync. So please check
-
it out.
-
K, so. I want to just demonstrate this very
-
simple Rails application. We'll go look at
a little
-
bit of code, and we're going to, we're gonna
-
add Sync to this application, and we're gonna
turn
-
it from a very classic, kind of CRUD-y Rails
-
application into real time.
-
So. A little, one note before we start on
-
code quality, this app is intentionally unfactored.
So there
-
is lots of places where you might apply some
-
design in an application that I have not,
for
-
this. But, the reason for that is so that
-
I can, we can refactor it to Sync a
-
little bit easier, without having to unfactor
it along
-
the way.
-
So, we'll go ahead and get started. So we
-
have a series of posts. And then when you
-
click on a post, you go to the post's
-
show action. On that post's show action, we've
got
-
a series of comments. That is no different
than
-
going to slash comments, other than it just
looks
-
a little bit different. So. We're not gonna
need
-
to be looking at the comments on the actual
-
resource. We're gonna be looking at it on
the
-
post resource. And that's it. So, you know,
say,
-
Hello RailsConf. Woo. Oh. Also, disclaimer,
I cannot type
-
in public. So this is gonna be very interesting.
-
So I can go ahead and I can add
-
a comment. I can delete a comment, because
it's
-
owned by me. I can go into posts that
-
I own and I can edit those posts. So
-
like that, right. Pretty simple.
-
OK. So let's bump this out a little bit.
-
So here is our application. You, same thing
as
-
we saw before. Our home controller is the,
the
-
home page. That showed the Jumbotron there.
And this
-
is all very bootstrappy. I'm sorry.
-
Here's our posts controller. Almost straight
out of the
-
box Rails resource here. Our comments controller
is nested
-
underneath our posts controller. We've got
a little bit
-
of additional calls here for access. Those
are defined
-
in helpers. This may not be how you would
-
do this in a real application, but for demonstration
-
purposes it, it fits the need. And I can
-
use these methods in the controller and also
in
-
the views.
-
OK. So let's take a look at the routes.
-
So you see we're not, we're not, we're not
-
cheating. So we've got nested comments under
posts. We've
-
also got tags. Let's take a look at tags
-
real quick. Tags are just a string attached
to
-
these various posts, and so if you click on
-
the Rails tag, you see there are three of
-
the four posts that are tagged with Rails.
And
-
then there is a list. So.
-
Let's say that we have this application, and
we
-
want to make it more awesome than it is
-
today. One of the things we really want is
-
we want to approximate what some of the apps
-
that are using heavy Javascript MVC frameworks
are accomplishing
-
with, with their responsiveness, and just
kind of like
-
updating the UI because something changed.
-
And so instead of basically rewriting our
entire frontend,
-
our entire presentation layer, and then also
creating an
-
API to support that Javascript presentation
layer, it's my
-
conjecture that, conj- it's my assertion here
that we
-
can use Rails the way Rails is intended to
-
be used, but still gain a good sub, a
-
good, large portion of, of this type of functionality.
-
So.
-
Let's go ahead and jump in.
-
All right, so the first thing we want to
-
do is open the gemfile and we want to
-
add a few gems. The first one is faye.
-
And the reason we need to add faye is
-
just for, for development. So we're gonna
use faye
-
for our browser to talk over websocket back
to
-
the server. And then faye also needs thin,
but
-
we don't like thin very much, so we're gonna
-
not require it by default. And then the last
-
one is Sync. K.
-
So we'll bundle install that. Told you I couldn't
-
type. There you go.
-
So now we've got, we've added sync to the
-
application. We need to go a couple steps
further.
-
The first is, in our application file, we
need
-
to add the Javascript for Sync. And so this
-
will be loaded as part of our normal application
-
Javascript everywhere. It will get pulled
in by the,
-
the, by the asset pipeline. And then also
we
-
need to go into our layout, our main application
-
layout, and there's another Javascript tag
that we need
-
to add. And that is going to be, we're
-
gonna use a little helper from Sync, adapter
Javascript
-
url.
-
And we'll talk about what all these mean,
hopefully
-
by the end of this. OK. Now we're good
-
to go. So what we need to do, before
-
we do anything else, is we need to start
-
up faye to run our web socket connections.
So
-
we can do that pretty easily. We can just
-
say rack up Sync.
-
Oh. I'm sorry. One more thing. We need to
-
just take a look at our generators. Oh, gosh.
-
K. There is now this install generator that
was
-
added by, by sync, so let's go ahead and
-
run that generator. That will create a rackup
file
-
and a configuration file.
-
So. Now that we have that, we can, we
-
can run this. Now this is going to run
-
faye in the background, and then here we can
-
just run our application. Come back over here
and
-
refresh and nothing has changed, but it all
continues
-
to work. So faye is running, but we're not
-
actually talking to it. But we know that it,
-
it's up. So. That's the important first step.
-
I don't particularly like having to open up
two
-
consoles, so one of the things I will do
-
is I'm gonna create a new file called, a
-
new proc file, and then inside of it I'm
-
gonna have a web entry. So you can't see
-
this, but this, I have to scooch down to,
-
so you can hear me, and it's killing my
-
back.
-
AUDIENCE: I think you can just stand up and
-
do it.
-
M.M.: Are you sure? All right. Exec, so rackup,
-
sync conf, sync ru. OK.
-
The other thing we need to do is come
-
back over here and add foreman. K. So, so
-
install that. Foreman is a gem written by
Heroku,
-
and so if you have lots of services that
-
you are coordinating, Foreman's a good way
to, to
-
start all of those. So now instead of going
-
to multiple terminals to open up, open this
up,
-
I can just say Foreman start, and it will
-
start both. So that's kind of handy.
-
All right. Let's take a look at one of
-
these, one of these pages. What I want is
-
I want to be able to come over here
-
onto this page and I want to add a
-
new comment, and then I want people to see
-
it as soon as it shows up, right.
-
So if I say see me, my, my browser
-
refreshes. But all of these browsers over
here won't
-
necessarily. So let's go to this guy. K.
-
So if I, for example, delete this one, it
-
still shows up in these other browsers. And
I
-
would really like it if it would disappear
as
-
soon as we ask it to. So let's make
-
that happen. To do that, we are going to
-
register our ActiveRecord models to be synced
in browsers.
-
And Sync is going to take care of all
-
of the communication from our Rails application,
all the
-
way down to the browsers for us.
-
So, to do that, there's a couple of things
-
we want to change. First is, we map up
-
our comment model. And we're gonna add this
little
-
declaration called sync_all to it. This is
going to
-
insert the sync DSL into the model. So now
-
whenever the model changes, it will try to
notify
-
the browsers that something has changed. We
also, we
-
need to open up our controller, and we need
-
to enable sync here as well. K.
-
And this is, again, just to, so the controller
-
knows to look for all of the messages from
-
the models that something has updated and
respond appropriately.
-
Let's take a look at the post show action.
-
Like I said, this is a mess of HTML.
-
This is not necessarily how I would do it,
-
but this is how it is. We've got kind
-
of two main areas of the page. The first
-
is at the top, where you've got all the
-
content for the blog post. So the title, the
-
user, those tags that are on the, the blog
-
post. Some editing links, if they are there,
and
-
then also the markdown of the body. OK.
-
Then after that we've got our comments section,
which
-
is going to iterate through the comments,
and because
-
we're showing, and then we're rendering a
partial for
-
the comment. And then after that, there's
also another
-
area to add a new comment, if you can.
-
So if you're logged in, you should be able
-
to comment. And if you're not logged in, you
-
shouldn't. And that's what that add comment
helper there
-
is guarding for us.
-
So, we want to make, we just want to
-
make this sync. It's pretty easy. What we're
gonna
-
do, we're gonna change this from render to
sync
-
partial, and then we're gonna say that our
resource
-
is our comment. So we've made it just a
-
little more verbose than what it was before,
but
-
sync needs that.
-
The next thing we're gonna do is we're gonna
-
add a new directory under app/views called
sync, and
-
under sync we're gonna add another folder
called comments.
-
And under comments, we're gonna add a new
file,
-
and that's gonna be called comments dot html
dot
-
erb. That's gonna be our partial, K.
-
So, when we say sync partial here, instead
of
-
looking at our normal template, it's gonna
go look
-
for the one in the sync directory. And for
-
the most part, we're just gonna take our trusty
-
old partial that we're using right now and
copy
-
and paste that. We can kind of just trim
-
some of this out. One of the caveats of
-
using sync is that we can't really do stuff
-
like this. We can't ask about the current
context
-
in which it's running, because this will get
pushed
-
out to everybody. So this, the same strategy
you
-
have for caching templates, caching partials
within your application,
-
you're gonna apply that same strategy to the
real
-
time updates as well.
-
And so stuff like this is probably just, just
-
gonna have to go, right. We can have the
-
user name, we have have what the body is.
-
But we really can't have all those editing
options.
-
AUDIENCE: [indecipherable - 00:15:35]
-
M.M.: Oh, did I? Thank you.
-
Let's rename this. So comment instead of comments.
So
-
that's our first step. The next change we
want
-
to make is, whenever a new comment comes,
we
-
want that to show up underneath, and so instead
-
of calling sync, we're gonna call sync.new.
This is
-
going to watch for new comments.
-
In here, the resource is going to have to
-
be a comment dot new, is that right? We
-
can probably go a little bit further and say
-
posts.comment dot new. K. All right.
-
So that's not a lot of changes. What we've
-
done is we've added sync to the repository,
to
-
the application. We've registered all the
Javascript. We've went
-
in, went ahead, moved some of our html from
-
the original locations to a new location under
sync
-
and instead of calling render, we're gonna
call sync
-
and sync new.
-
AUDIENCE: [indecipherable - 00:16:47]
-
M.M.: What's that?
-
AUDIENCE: [indecipherable - 00:16:49]
-
M.M.: Post, yes. Thank you. Live coding, ladies
and
-
gentlemen.
-
Yeah. I transposed the plural. There you go.
-
AUDIENCE: Pair programming to scale.
-
M.M.: Pair programming to scale. All right.
-
So let's see if this works. What I'm gonna
-
do is I'm gonna refresh this page. I'm gonna
-
refresh this page. I'm gonna refresh this
page. Now
-
Firefox is not logged in. Safari here is logged
-
in here by Stanley, who's back there somewhere,
and
-
then Chrome is logged in by me. So let's
-
see if this works. Who wants to place a
-
bet?
-
Does this work? Anybody know?
-
All right. Let's see if it works. All right.
-
There we go. Does this work? K. Yay!
-
So what's nice about this approach is that
this
-
is gonna go out no matter how many clients
-
you've got connected, theoretically. Every
time your, your assets
-
change, your resources change in your application,
they can
-
be notified in real time. K.
-
And we didn't have to write a whole bunch
-
of Javascript. We didn't have to change how
we
-
were architecting our presentation layer.
We're gonna use the,
-
the same infrastructure that we're using today.
All right.
-
OK. Now, because of this, I kind of lost
-
my ability to, to edit. And I would like
-
to have that back. So what I want to
-
do is, in this loop, where we're saying, you
-
know, we're gonna add this missing partial,
what I
-
really want to do is I want to say,
-
if you can edit the comment, right. And that's
-
current user. What I really want to say is
-
that if I can edit, I want to have
-
the same partial I had before, right. But,
if
-
I can't, then I want to use the one
-
that is going to be synced. K.
-
K. So, it's a small change. But what it's,
-
what it's saying is, is that, if I have
-
permissions to edit it, I don't want it to
-
be syncing, I don't want to be notified if
-
it changes, because I am likely the browser
that's
-
gonna be changing it. And, and I really want
-
the tools to be able to edit and delete.
-
So I'm gonna just come back here and refresh
-
this UI, and you'll notice now, because of
that,
-
I have my tools back. My edit and delete.
-
So I can come back over here and say
-
yes, it does work. See, that updates there.
It
-
looks like we've got a little bug.
-
And then eventually I can actually delete
it as
-
well. And it gets rid of it. K.
-
And there's another bug with this. Do you
guys
-
want to see what it is? It's pretty fun.
-
Here is a, well, let's go to this one.
-
Here is a blog post that doesn't have any
-
comments yet. I'm gonna go onto this different
blog
-
post, right, and, say we gotta bug. When I
-
do that, my comment is showing up on this
-
different blog post, right. Because it's,
right now we're
-
looking for all comments whenever it gets
updated, we're
-
gonna add it to this page. So what we
-
need to do is we need to scope these
-
comments to this page. So let's add that really
-
quick.
-
We're gonna come back here to, come back here
-
to our comment model, and we're gonna add
a
-
new scope. Now, this is gonna be different
than
-
a normal scope. Might be a redundancy, but
sync
-
needs it. So let's add it, called by_posts.
And
-
it's gonna take a lambda, and we're gonna
give
-
it a post and we're gonna say where post
-
id is post id. K.
-
K. So we've just added a scope for post.
-
Then we're gonna come over here into our sync
-
partials. And we're going to add that scope
here.
-
So let's, let's see scope dot by_posts. And
let's
-
also add that to this one. K.
-
So now if we refresh this, come over here,
-
and now I'm logged in as Stanley. I say,
-
oh hi. It shows up here, which is what
-
we expect, but on this other one it does
-
not, K. And if I refresh this we'll get
-
rid of that comment. So scoping is, is easy
-
as declaring a new scope on your model, in
-
the same syntax that we're using for normal
scopes.
-
And then whenever we render out our partials,
we
-
just have to, we have to reference that scope.
-
M.M.: Why do we need what?
-
M.M.: The scope in both? Cause there are two
-
different partials. It, it would be possible
to-
-
AUDIENCE: [indecipherable - 00:22:59]
-
M.M.: No. It affects both. The scope affects
both.
-
The reason why there are two partials, here,
is
-
that whenever a new comment comes into existence,
we
-
want that to be listed. So we can move
-
that around, theoretically, I believe, if.
Whoa.
-
Nevermind. Let's not touch that. Live coding.
-
All right. So sync is a pretty cool little
-
library. It does quite a lot for us. What
-
it's going to do, is it's going to hold
-
a connection via web socket to a server, and
-
then it's going to put mechanisms within Rails
to
-
talk to that, that web socket, and then when
-
our resources change, it will render those
templates and
-
push that out to that web socket, which the
-
clients will then pull down, K. So without
re,
-
without rearchitecting our presentation tier,
we are able to
-
take advantage of real time, and able to do
-
it without a major change to how we're organizing
-
or architecting our templates, our files.
-
We can go just a little bit further, as
-
well. So let's open a Rails console, K, and
-
we'll say. Just get, just a comment out of
-
here. All right. So I got this comment right
-
here, which is Jason saying that he's watching,
but
-
he's kind of on a delay because he's not
-
actually in the room, K.
-
What we can say here is sync model dot
-
enable, and this will allow all changes that
happen
-
within our process, that's not running on
the web
-
server, still a Rails process, but we're not
actually
-
on running on the web server. It's a separate
-
process. Maybe a background job. But now all
of
-
our changes that we make can also be reflected
-
in real time as well.
-
So let's pull this guy over. And watch that
-
happen. So we can change this to, what should
-
Jason say? Say, I don't know, real time. K,
-
so let's pull him out. You see that his
-
text is right here. I'm watching, kind of.
When
-
I call save it will change, and it updates
-
right here, in real time. And duplicate. Why?
Chris?
-
Why?
-
Applettes.
-
AUDIENCE: Wait till afterwards.
-
M.M.: Afterwards? All right.
-
OK. Let's continue and add this to some of
-
the other pages as well. So let's go to
-
post. Let's do the same thing. We want to
-
sync our posts as well. And our posts controller,
-
we want to enable sync here as.
-
Enable sync on our post controller and in
our
-
posts model. So let's go ahead and take a
-
look at our post index page. Our index page,
-
where we're listing all the posts, we're gonna
go
-
through and render the post. And then, if
we
-
have, if we can, we'll add, we'll have a
-
button to add a new post. If we look
-
at that post partial, you notice here, again,
we've
-
got some logic in here determining whether
or not
-
we can edit it, or whether or not we
-
can remove it.
-
So this logic is problematic when we're talking
about
-
a cache template that's gonna get pushed out
to
-
everybody, cause not everybody's gonna have
the same amount
-
of permissions. So what we'll have to do is
-
we'll have to just take that out. And I'm
-
gonna take it out and put it into the
-
index template.
-
Well. Actually, I'm just gonna take it out
of,
-
of this view altogether. So, again, in order
to
-
change our template from a static template
to a
-
real time template, we're gonna say sync and
partial
-
is a post. And then our resource is also
-
gonna be that same post, and then, if we
-
get a new post, it just lists him down
-
below. We don't, probably don't need to scope
on
-
this one. The big problem we have is all
-
of this edit information. So let's go over
here
-
to posts and get rid of that guy. So
-
I'm just gonna remove some, some code here.
I'm
-
gonna remove all of this editing. Anything
that's gonna
-
talk to current user, the current request
is not
-
gonna work. So let's get rid of that.
-
And now let's take a look at, take a
-
look at our, our post pages. I don't know
-
what that is.
-
We're asking for posts, it doesn't exist outside
of
-
that block. So we're gonna say post dot new.
-
OK. So, again, user not logged in, user logged
-
in, and as a different user logged in. So
-
if I come over here, I want to add
-
new post. See if it works. And let's add
-
that.
-
So, Stanley added this post. It shows up immediately
-
on, on Mike's browser. And it also shows up
-
in the not logged in browser. Let's come over
-
here. We'll, we'll say congrats. Now.
-
This browser over the right, the comment is
not
-
updating, right. Let's go back over here.
So here,
-
we've got one comment. Stanley says, I know.
And
-
that, that one comment here is still not updated.
-
So we've got changes happening on a sub-resource,
but
-
it's not changing our template. Thankfully
there's a really
-
nice DSL to make that happen. So we'll go
-
to our comment controll- or, comment object,
and we'll
-
say sync touch post. K.
-
So this is similar to normal touch. If you
-
want, have a resource that you want to touch
-
through an association whenever it updates,
it works just
-
the same, only it's a special one that'll
work
-
for sync. So let's save that and refresh all
-
of these browsers. K. So now they all have
-
two comments. OK.
-
I come over here. Let's have Stanley add one
-
more, add one more comment. Man, Chris. Now
the
-
comments are updating multiple times. I'm
curious to why
-
that is. It wasn't doing that an hour ago.
-
What did I miss? OK.
-
There's one more, there's one more review
of posts
-
here, and that is the actual post page. So
-
we can edit this. So let's say it sort
-
of works, but now this page isn't updating
and
-
this page isn't updating, right. So we, I've
updated
-
this post, but the other browsers aren't updating
on
-
the show page. The reason for that is because
-
we're not syncing the template on that page.
So
-
really quick we'll see, we'll show you just
how
-
easy it is to do that. We'll come over
-
here to show. We have this same information
where
-
we're pawing out all of these links determining,
you
-
know, whether or not we can edit. I'm gonna
-
punt on that. I'm just gonna put that down
-
below. So it's not gonna be part of any
-
template. So if you hit this page and you
-
can edit it, we're going to show you those
-
links. But it's gonna be outside of the, outside
-
of the, the partial.
-
So I'm just gonna sit. We're gonna sync a
-
new partial and it's gonna be called, oh my
-
gosh. I cannot type. It really is so uncomfortable.
-
So a new partial, we're gonna call this postfull,
-
because we have the full body embedded in
it.
-
And the resource is going to be that post
-
object. And then that's really it. We come
back
-
here to our sync directory under posts, create
a
-
new file, and we'll save this as postfull.
-
And then we'll come back, restart all of these
-
browsers, and come back here and edit this
and
-
so it really does work. What?
-
What am I missing?
-
AUDIENCE: [indecipherable - 00:34:01]
-
M.M.: I did refresh the browsers. Let's refresh
it
-
one more time.
-
AUDIENCE: Did you try rebooting?
-
M.M.: Huh. All right. Again. It worked an
hour
-
ago.
-
So, that's sync. I'm out of time. But we've
-
used this on some internal apps dealing with
monitoring.
-
And instead of pulling, continually asking
for new information,
-
just organizing a Rails app like you always
have
-
with templates and having those templates
update whenever resource
-
is changed has been just a really, really
great,
-
fantastic thing. There are caveats. It's a
little touchy,
-
as you can see. But it's definitely been getting
-
better over time.
-
I would just like to leave you with this
-
little pitch, that Rails has benefited, over
the years,
-
from being first to, to popularize certain
approaches for
-
web development. It was there at the very
beginning
-
with Ajax. It was there are the very beginning
-
with REST. I, I strongly feel that if we
-
are not able to do real time information within
-
Rails that people will move on from Rails.
And
-
I totally think that you don't need to. I
-
know that there's a lot of functionality that
is
-
very difficult to do with Rails as it is
-
today, and so people are looking outside of
Rails
-
for the presentation. But there are so many
advantages
-
to rendering your html on the server that
we
-
just need to think a little bit differently
and
-
a little bit better about it.
-
So, I'll open it up to questions.