Cool screencast Ryan. But wouldn't you consider sending and executing raw javascript a serious security flaw? E.g.does anything prevent me from redirecting every other user to another website?
Thank you for all the amazing material you put out.
@Jingwen, The approach I show here is very similar to Pusher, but I don't know if they use EventMachine internally. the RackAdapter inside of Faye does use EventMachine, the Node.js server version does not.
The beautify of this approach is that you don't have to worry about any of this. Your Rails app does not need to use EventMachine because it just sends a quick post request to Faye.
It took me a little to figure out that for best results web browser must support WebSockets. I was using Opera 11 and Firefox 4 in which WebSockets are disabled by default.
@rbates If faye is using eventmanchine? Do I need to make sure my implementation in rails is asynchronous by using eventmachine as well? From my understanding, rails is blocking the IO.
@rbates Is the implementation of faye any difference from the pusherapp(http://webpulp.tv/post/1626829659/pusher-app-martyn-loughran)? Are they both using eventmachine?
It's so awesome! I have been looking for the same stuff for a long time...(even thinking of building one).
@rbates Sorry, I was meaning including the source code of application.js on this page. Of course, application.js should be included by rails application layout as well.
@Oleg, I haven't tried Juggernaut because Faye worked so well for me and did exactly what I needed, but Juggernaut does look great as well. I should give it a try. Thanks for the suggestion.
@ybart, application.js is included automatically by the :defaults option.
@Benoit, if you're using Heroku you probably don't want to worry about managing servers and scaling. In that case I recommend using Pusher. It's also listed on the Heroku Add-ons page.
Wondering how to secure which channels people can listen to. As far as I understand, in theory anybody can listen to your messages through javascript in this example.
Anyone been able to do this with RJS? I don't know what to put in the "form_for" since this is not in the new action of the comments but in any show of the articles, photos, etc
Tim,
I'm on Rails 3.0.5 and Ryan's instructions work for me precisely.
In Application Controller, you only need one line of code:
include UrlHelper
... an the rest is in UrlHelper.
i had to overwrite url_for in application_helper not in application_controller .. is that new in rails 3.0.5 ?
Not sure why, but that is how it works ..
@Phillip Hallstrom: in the scope of the iterator, article will be passed in and you won't see an article you've exposed via the controller. This is probably fine though, because you're not likely to need to deal with the exposed article inside that iterator.
As to differentiating, the same could be said of methods in models.. "How do I know if it's a method or a variable?!" I can only say that it gets easier with time and is made even easier by tools integrating things like (exuberant) Ctags.
The simple fact of the matter is that instance variables are meant to be referenced internally by an instance of a class. Outside objects (like an instance of ActionView) having direct access to another object's internal state is an excellent way to increase coupling and doesn't abide by OO best practices like "programming to an interface".
This approach was guided largely by my attempt to adhere to OO design advice offered by tomes written by people much smarter than myself, such as the GoF's Design Patterns book.
It looks like I might be the only one, but for some reason I don't like this at all. I've always liked instance variables in the view because the @ makes it very clear where the data is coming from -- the controller. Everything else is either local or a helper method. This makes that much harder to see at a glance.
The other issue is what happens if on an article page you decide to have a "related articles" list and do a loop like:
<% for article in related_articles %>
What happens with 'article' in this case after the loop completes? Seems messy. Yes, I could change 'article' to 'a' or something, but the chance for collision bothers me. Even having to remember that in this case article is not from the controller, but a local variable bother me...
It looks like the posted versions of cropper.rb are not working with Paperclip 2.3.8. Does anyone have an updated version that works with the newest paperlcip?
Very nice... I would have stopped before installing the gem however. Your example of just adding a couple of methods makes things clear and concise but adding the gem unnecessarily hides the simple logic away making it hard to see exactly what is going on without delving into the gem code/docs.
@MissingHandle: I never thought the view shouldn't make model calls as it is the necessary data to display. Which models to use is the controller's responsibility.
Outside of the DRY-ing up of the controller code, I just am not realizing the advantage of using a controller method call rather than an instance variable. After all, the method is returning the same object. However, I am looking at this from one simple (BUT AWESOME) demonstration. I'll definitely do some experimenting.
@Bill Christian - to add to @moabite's comments, I think the controller is supposed to interact and know about models. Certainly, the view shouldn't make model calls, but the controller has to - it's the middle man between the two, no? Or maybe I miss your point?
I think you keep model/controller responsibilities separated by keeping the controller focused on scoping models and referring to as few model attributes as possible.
Is there another implementaion of the .where command for rails 2.3.4? I have everything else working but the function to limit the list to the typed in name is not working as rails 2.3.4 does not have the .where command...
@Stephen Caudill, thank you! that makes so much sense. We've been doing too much specific assertion where if we change the name of an id of say, a link, things break.
Also, your blog post made me think that this application of the Single Responsibility Principle makes a lot of sense to integrate into cucumber step definitions down to maybe the link/id/css class level? Instead of calling a link or id directly, you call a method that returns the link/id. That way if you change a link or id, there's only one place to change it...that seems like it might cure the brittleness i'm hurting from and keep the features exact.
Thanks for the fantastic railscast! I've found a minor bug that I was wondering if anyone could explain to me - I'm a rails newb so I have a lot of gaps in my knowledge. When the authentications_controller hits the line:
> NameError in AuthenticationsController#create -
uninitialized constant MultiJson
But, I can print the env information to the logger if I don't try to render the text. Here's a gist of the complete code snippet with the logger lines, which pass, and the render line, which fails:
From the perspective of the view, it has to 'know' a priori how the controller is providing data, either instance variables or expose'd methods etc. I've been changing some controllers over to using respond_to/respond_with ala episode 224 (http://railscasts.com/episodes/224-controllers-in-rails-3). The only stumbling block for me is that the view template still needs to know how the controller is providing data, even though the controller specified 'respond_with widgets' (or 'respond_with @widgets'). Non-templated requests, e.g. /widgets/index.xml, are picking up the correct data, but I don't see a clean way of determining in the view template (say index.html.haml) what the controller said to respond_with. The real pain point here is when I'm rendering partials. At the moment I'm having to call the partial with a :locals hash.
Of course, I could be way out in left field here. If I am, please leave some breadcrumbs so I can get back home.
Not to be too much of a theorist, but doesn't this blur the model & controller responsibilities. With decent_exposure you are replacing the model object with a controller helper method. I guess if I look at it as simply a wrapper for the model object it's a wash between the two. Just my initial reaction was we are bending MVC rules some. Anybody else get that feeling?
My data in json is not being displayed in the order of [id, name] which I guess is required for the plugin to work. Can anyone tell me how to re-sort the json data or how to use the jsonContainer option for the plugin?
Excellent videos, thanks, I was trying it with a 2.3.10 rails app to 3.0.5 most of the work is already done, is booting normally.
But I found a really ugly bug, the default layout is not working, actions from controllers are rendering without the default layout but actions with specific layout option on render are working.
Does anyone have any suggestions on how I would tell my app to not load any pictures and javascript files when rendering the pdf's? Perhaps in an initializer or something?
if you find that you have rails 3 gems conflicting with your script/generate daemon mailer...
error like: http://pastie.org/1736483
Then this version of the plugin will work for you: https://github.com/jmazzi/daemon_generator
You can also solve the problem by implementing bundler into your rails 2.3.X application:
http://ryanbigg.com/2010/08/three-dot-oh/
I got it working using the first technique and didn't bother to try the second. happy coding!
About view testing with rspec and decent_exposure:
http://blog.angelbob.com/posts/379-RSpec-Haml-and-decent-exposure-are-incompatible-That-d-be-odd----published-rails
Just mock it:
view.should_receive(:entry).at_least(:once).and_return(my_entry)
Cool screencast Ryan. But wouldn't you consider sending and executing raw javascript a serious security flaw? E.g.does anything prevent me from redirecting every other user to another website?
Thank you for all the amazing material you put out.
You could use Faye to allow live updating of the browser as you edit your code.
1) Setup watchr to watch your files (I suggest SASS and HAML) and get it to execute a curl request (crude but effective) when they change.
2) Get Faye to reload the page when it receives the message from watchr.
3) Start editing and watch the page update as you save!
Has anyone tried this same thing with Amazon SNS? Interestingly I am not finding much of comparison between pusherapp and the like to SNS.
@ybart, oops, I forgot that. It's up there now.
@Jingwen, The approach I show here is very similar to Pusher, but I don't know if they use EventMachine internally. the RackAdapter inside of Faye does use EventMachine, the Node.js server version does not.
The beautify of this approach is that you don't have to worry about any of this. Your Rails app does not need to use EventMachine because it just sends a quick post request to Faye.
@Javi, done.
It took me a little to figure out that for best results web browser must support WebSockets. I was using Opera 11 and Firefox 4 in which WebSockets are disabled by default.
Very interesting subject! Websockets are definitely in my TODO list.
Ryan, could you please add the link to async_sinatra & others to the show notes?
Thanks!
@rbates If faye is using eventmanchine? Do I need to make sure my implementation in rails is asynchronous by using eventmachine as well? From my understanding, rails is blocking the IO.
Once again, thanks for the post!!!
@rbates Is the implementation of faye any difference from the pusherapp(http://webpulp.tv/post/1626829659/pusher-app-martyn-loughran)? Are they both using eventmachine?
It's so awesome! I have been looking for the same stuff for a long time...(even thinking of building one).
@rbates Sorry, I was meaning including the source code of application.js on this page. Of course, application.js should be included by rails application layout as well.
@Oleg, I haven't tried Juggernaut because Faye worked so well for me and did exactly what I needed, but Juggernaut does look great as well. I should give it a try. Thanks for the suggestion.
@ybart, application.js is included automatically by the :defaults option.
@Benoit, if you're using Heroku you probably don't want to worry about managing servers and scaling. In that case I recommend using Pusher. It's also listed on the Heroku Add-ons page.
Hi @Ryan, this is great, Got what i needed when I needed...
thanks a lot
sameera
@Benoit It should work as long as you keep your faye instance running in a different server.
How compatible is this solution? Does it work on mobile browsers? Does it automatically change transport if websockets are disabled?
Thanks for this screencast!
Faye is awesome!
@James: Thanks, sounds good!
Thanks a lot for this screencast! Do you think Faye could work on Heroku?
@Nico you can implement authorization as an extension to the server -- see 'Extensions' docs at http://faye.jcoglan.com/ruby.html
Really great cast ! I was recently searching for this kind of solution without finding anything I was happy with. Thanks to make me discover Faye.
In the code, I think application.js should be included as well.
Just been doing something very similar with EventMachine as I wanted to interface directly with AS3 over sockets.
I'll have to dig around this bayeux protocol and see if Faye can do the job easier.
Nice episode, thank you.
What about using juggernaut for server push?
Its nice solution too with support of different server-push methods.
Wondering how to secure which channels people can listen to. As far as I understand, in theory anybody can listen to your messages through javascript in this example.
I knocked up seedbank to give your seeds a little structure like this;
git://gist.github.com/900969.git
https://github.com/james2m/seedbank
could this work with nested forms?
where each element has an autocomplete box
I tried it but the ids are identical to the last existing obj passed through fields_for
Anyone been able to do this with RJS? I don't know what to put in the "form_for" since this is not in the new action of the comments but in any show of the articles, photos, etc
Tim,
I'm on Rails 3.0.5 and Ryan's instructions work for me precisely.
In Application Controller, you only need one line of code:
include UrlHelper
... an the rest is in UrlHelper.
@Ryan : how do you convert to decent exposure something like episodes controller on the railscasts.com app?
e.g
https://github.com/ryanb/railscasts/blob/master/app/controllers/episodes_controller.rb
I was having issues getting the add function to work properly in Rails 3 + jQuery too, but this solution from ceneon solved it for me:
--------------
Change the link_to_function to:
link_to_function(name, "add_fields(this, '#{association}', '#{escape_javascript(fields)}')" )
notice the change from \" to ' ... otherwise they would be converted to &, and not a javascript string delimitor.
i had to overwrite url_for in application_helper not in application_controller .. is that new in rails 3.0.5 ?
Not sure why, but that is how it works ..
@Phillip Hallstrom: in the scope of the iterator, article will be passed in and you won't see an article you've exposed via the controller. This is probably fine though, because you're not likely to need to deal with the exposed article inside that iterator.
As to differentiating, the same could be said of methods in models.. "How do I know if it's a method or a variable?!" I can only say that it gets easier with time and is made even easier by tools integrating things like (exuberant) Ctags.
The simple fact of the matter is that instance variables are meant to be referenced internally by an instance of a class. Outside objects (like an instance of ActionView) having direct access to another object's internal state is an excellent way to increase coupling and doesn't abide by OO best practices like "programming to an interface".
This approach was guided largely by my attempt to adhere to OO design advice offered by tomes written by people much smarter than myself, such as the GoF's Design Patterns book.
It looks like I might be the only one, but for some reason I don't like this at all. I've always liked instance variables in the view because the @ makes it very clear where the data is coming from -- the controller. Everything else is either local or a helper method. This makes that much harder to see at a glance.
The other issue is what happens if on an article page you decide to have a "related articles" list and do a loop like:
<% for article in related_articles %>
What happens with 'article' in this case after the loop completes? Seems messy. Yes, I could change 'article' to 'a' or something, but the chance for collision bothers me. Even having to remember that in this case article is not from the controller, but a local variable bother me...
+2 cents.
It looks like the posted versions of cropper.rb are not working with Paperclip 2.3.8. Does anyone have an updated version that works with the newest paperlcip?
Very nice... I would have stopped before installing the gem however. Your example of just adding a couple of methods makes things clear and concise but adding the gem unnecessarily hides the simple logic away making it hard to see exactly what is going on without delving into the gem code/docs.
Thank you!
What if your data is obtained from an API (going through net), not from your own DB... then how do you use Kaminari (or will_paginate) ?
I figured out what the issue was with the "uninitialized constant MultiJson". I just had to add:
> gem "multi_json"
to my Gemfile, bundle install, restart the server and now I'm all good :)
@MissingHandle: I never thought the view shouldn't make model calls as it is the necessary data to display. Which models to use is the controller's responsibility.
Outside of the DRY-ing up of the controller code, I just am not realizing the advantage of using a controller method call rather than an instance variable. After all, the method is returning the same object. However, I am looking at this from one simple (BUT AWESOME) demonstration. I'll definitely do some experimenting.
@Bill Christian - to add to @moabite's comments, I think the controller is supposed to interact and know about models. Certainly, the view shouldn't make model calls, but the controller has to - it's the middle man between the two, no? Or maybe I miss your point?
I think you keep model/controller responsibilities separated by keeping the controller focused on scoping models and referring to as few model attributes as possible.
Is there another implementaion of the .where command for rails 2.3.4? I have everything else working but the function to limit the list to the typed in name is not working as rails 2.3.4 does not have the .where command...
Thanks!
@Stephen Caudill, thank you! that makes so much sense. We've been doing too much specific assertion where if we change the name of an id of say, a link, things break.
Also, your blog post made me think that this application of the Single Responsibility Principle makes a lot of sense to integrate into cucumber step definitions down to maybe the link/id/css class level? Instead of calling a link or id directly, you call a method that returns the link/id. That way if you change a link or id, there's only one place to change it...that seems like it might cure the brittleness i'm hurting from and keep the features exact.
Thanks for the fantastic railscast! I've found a minor bug that I was wondering if anyone could explain to me - I'm a rails newb so I have a lot of gaps in my knowledge. When the authentications_controller hits the line:
> render :text => request.env['omniauth.auth'].inspect
The error is:
> NameError in AuthenticationsController#create -
uninitialized constant MultiJson
But, I can print the env information to the logger if I don't try to render the text. Here's a gist of the complete code snippet with the logger lines, which pass, and the render line, which fails:
git://gist.github.com/896700.git
Any idea on what's going on here?
Thanks!
As long as we're talking theory & coupling...
From the perspective of the view, it has to 'know' a priori how the controller is providing data, either instance variables or expose'd methods etc. I've been changing some controllers over to using respond_to/respond_with ala episode 224 (http://railscasts.com/episodes/224-controllers-in-rails-3). The only stumbling block for me is that the view template still needs to know how the controller is providing data, even though the controller specified 'respond_with widgets' (or 'respond_with @widgets'). Non-templated requests, e.g. /widgets/index.xml, are picking up the correct data, but I don't see a clean way of determining in the view template (say index.html.haml) what the controller said to respond_with. The real pain point here is when I'm rendering partials. At the moment I'm having to call the partial with a :locals hash.
Of course, I could be way out in left field here. If I am, please leave some breadcrumbs so I can get back home.
Not to be too much of a theorist, but doesn't this blur the model & controller responsibilities. With decent_exposure you are replacing the model object with a controller helper method. I guess if I look at it as simply a wrapper for the model object it's a wash between the two. Just my initial reaction was we are bending MVC rules some. Anybody else get that feeling?
if you are stuck with "uninitialized constant UsersController::UserMailer" error try adding this to the initalizer :
require "development_mail_interceptor"
and don't forget to change :
ActionMailer::Base.register_interceptor(DevelopmentMailInterceptor) if Rails.env.development?
this should be a default option on the next release of rails? no?
My data in json is not being displayed in the order of [id, name] which I guess is required for the plugin to work. Can anyone tell me how to re-sort the json data or how to use the jsonContainer option for the plugin?
Thanks!
Excellent videos, thanks, I was trying it with a 2.3.10 rails app to 3.0.5 most of the work is already done, is booting normally.
But I found a really ugly bug, the default layout is not working, actions from controllers are rendering without the default layout but actions with specific layout option on render are working.
Here is the code for a better understanding:
https://gist.github.com/895355
Any thoughts are welcome.
Does anyone have any suggestions on how I would tell my app to not load any pictures and javascript files when rendering the pdf's? Perhaps in an initializer or something?
Hey guys,
if you find that you have rails 3 gems conflicting with your script/generate daemon mailer...
error like: http://pastie.org/1736483
Then this version of the plugin will work for you: https://github.com/jmazzi/daemon_generator
You can also solve the problem by implementing bundler into your rails 2.3.X application:
http://ryanbigg.com/2010/08/three-dot-oh/
I got it working using the first technique and didn't bother to try the second. happy coding!
About view testing with rspec and decent_exposure:
http://blog.angelbob.com/posts/379-RSpec-Haml-and-decent-exposure-are-incompatible-That-d-be-odd----published-rails
Just mock it:
view.should_receive(:entry).at_least(:once).and_return(my_entry)
@Jeroen:
Check out Xvfb
http://www.google.com/search?sourceid=chrome&ie=UTF-8&q=xvfb
I've got my tests running on a linux server (ubuntu) with cucumber, capybara, xvfb and firefox. Working like a champ.