Meteor is running on Node.js. As javascript was a client side only script it lacked functionality to make it run on the server, for example there was no api for IO interaction in javascript (no way to access the hard drive), the team of Node.js build a non blocking IO api and since node is recent the api is very modern.
Now Node.js runs on top of V8 , and all (that i now of) server side javascript plaforms run on top of Node.js. Backbone.js is a client side technology so it not related to Node.js. For an extensive explanation of what is cool about node and what it really is read this thread http://stackoverflow.com/questions/3436335/could-node-js-replace-ruby-on-rails-completely-in-the-future
but i needed to do it for MongoDB using Mongoid so you can see all of the little changes here that i had to make to get it to work https://github.com/ndgiang84/oauth-sample
Ryan, you just read my mind! I've been looking for a good resource on best practice for this so having you create a post like this is a real treat since there's not much info for best practices.
Wow! Super impressive. Thanks a lot Ryan. I was intrigued by backbone.js, but it really seemed confusing to me. Meteor has a lot of qualities that Rails had that made me want to dive in. I look forward to using it
Well meteor looks as magical as Rails did the first time i saw Rails, I mean , where is the db connection set? I know everything is work via CoC but wow that is one slim app.
I believe that is even if meteor or similar clients side technologies don't replace Rails eventually there is a very high possibility they could replace sinatra apps since I use sinatra for very similar applications and meteor does seems to be a quicker/slimmer/awesomer solution.
Each time you create a new MIME type name (application/vnd.example.v1, application/vnd.example.v2, ...), a kitten is hurt! don't do that! that's bad!
Use MIME parameters instead: application/vnd.example; version=1, application/vnd.example; version=2, ... (version=, or level=, or v= or whatever you want, this is part of your design).
The semantic of a MIME type is that every document "flagged" with that type share the same "lineage", and that two different names are not related, even if they share a same prefix.
By incorporating a version identifier into the MIME type name, you are making the names distinct and are in the same case as if your V1 API was using text/html documents whereas your V2 now uses image/png pictures instead.
One thing I have started doing recently for a few APIs is to support versioning simply using folders with RABL templating. Depending on your situation, it can greatly reduce code duplication. Simply setup a single api controller and then render the corresponding template based on a version parameter i.e render "#{params[:version]}/show" and then create templates for each version (users/v1/show, users/v2/show). Since the controller between versions is typically largely unchanged in most cases, this may be an alternative approach. If anyone is curious for more details, perhaps I can add a guide to the RABL wiki.
Would be good to expand this tutorial on how to secure your API with tokens or usernames and passwords? Also the possibility of using CanCan to authorize the api methods.
I would have it a guess the best place to start would be to create a api base class where most of that work could be done?
I really liked the page caching, because page serving is 100 times faster when using nginx compared to fragment caching and action caching. But I have some doubts, and I would really appreciate if you can answer these.
I have a large site and a lot of content like most read, recent content etc on almost each page. If i use page caching Do i delete all page cache like mentioned in this tutorial
If I use the above technique, I guess for users it will work fine but when Google will come to read the site, won't it take too long to read pages, because they might not be in cache at all that time.
If I use delayed jobs to generate page in cache in backend. Will that be a reasonable solution?
I'm just here to say, It's the year 2012 and i find this tutorial still useful, thanks Ryan! =D, I'm a student from Mexico and learning ruby on rails has become very easy thanks to your videos!
I hope you can keep doing videos for more years, thanks again and see ya ! =D
I'm just starting to look at rubber, but it looks like it's doing much of what I was building by hand. Can you share how you configured it to work with RDS?
You can definitely use for resources other than User. For instance, originally had User resource that included a bunch of additional information regarding the user's profile (address, age, phone #'s, etc.).
I decided that these attributes should be part of a different resource called RenterProfile (it's an app for renters), leaving nothing but the email address and password in the User resource. So I setup the appropriate controller, model, views and DB migration for this renter_profile resource. Once I had everything working (all the renter_profile fields within a single page/form, I then moved on to implementing a wizard for the renter_profile resource.
I followed Ryan's example pretty much verbatim simply swapping in renter_profile in place of user. I let my renter_profiles_controller perform the initial #create action with just a few basic fields (similar to creating the User with only the email and password). Then I created a renter_profile_steps controller (of course including the wicked gem same as Ryan's example). I placed the remaining attributes I wanted for the renter_profile into multiple form view files within the ~/views/renter_profile_steps directory.
The only hiccup I encountered was that get "renter_profile/steps" somehow ended up in my routes.rb file which messed everything up. Not sure how it ended up there (maybe wicked created it, but unlikely) or my coding partner did it without remembering... Regardless, with it removed, the renter_profile_steps_path began working correctly.
same here. I've added that line in app controller but error is still on my page :
edit:
solved - just add that lines: private
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
to the app/helpers/application_helper.rb ;)
I'm using form_tag not form_for. I got the autocomplete working but when I submit the form, no parameters are passed. If I remove the javascript and submit the form, my inputs are passed as expected. Any ideas?
You can also use just one shared db connection as mentioned on: platformatec-blog
ruby
classActiveRecord::Base
mattr_accessor :shared_connection@@shared_connection = nildefself.connection@@shared_connection || retrieve_connection
endend# Forces all threads to share the same connection. This works on# Capybara because it starts the web server in a thread.ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
* executing `deploy:check_revision'
fatal: ambiguous argument 'origin/master': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions
WARNING: HEAD is not the same as origin/master
but it's worked fine to call cap deploy:cold every time.
Fixed, thanks for bringing this to my attention.
Meteor is running on Node.js. As javascript was a client side only script it lacked functionality to make it run on the server, for example there was no api for IO interaction in javascript (no way to access the hard drive), the team of Node.js build a non blocking IO api and since node is recent the api is very modern.
Now Node.js runs on top of V8 , and all (that i now of) server side javascript plaforms run on top of Node.js. Backbone.js is a client side technology so it not related to Node.js. For an extensive explanation of what is cool about node and what it really is read this thread http://stackoverflow.com/questions/3436335/could-node-js-replace-ruby-on-rails-completely-in-the-future
at my day job, i just created an OAuth 2.0 provider and consumer demo with the help of this tutorial http://unhandledexpression.com/2011/06/02/rails-and-oauth-plugin-part-1-the-provider/ & http://unhandledexpression.com/2011/06/28/rails-and-oauth-plugin-part-2-the-consumer/ and that tutorial is for sqlite or mysql.
but i needed to do it for MongoDB using Mongoid so you can see all of the little changes here that i had to make to get it to work https://github.com/ndgiang84/oauth-sample
Ryan, you just read my mind! I've been looking for a good resource on best practice for this so having you create a post like this is a real treat since there's not much info for best practices.
+1 for Ember.js
Ya, A similar episode with Ember JS would be super useful. How does Node JS fit into all this?
Wow! Super impressive. Thanks a lot Ryan. I was intrigued by backbone.js, but it really seemed confusing to me. Meteor has a lot of qualities that Rails had that made me want to dive in. I look forward to using it
Why not just sign all params on the client and server side using SHA1?
Client:
api_key = SHA1(params, secret_salt, date)
Server:
SHA1(params, secret_salt, date) == api_key
Well meteor looks as magical as Rails did the first time i saw Rails, I mean , where is the db connection set? I know everything is work via CoC but wow that is one slim app.
I believe that is even if meteor or similar clients side technologies don't replace Rails eventually there is a very high possibility they could replace sinatra apps since I use sinatra for very similar applications and meteor does seems to be a quicker/slimmer/awesomer solution.
I have the same problem, did you solve it?
I'm fifth-ing that! tokens and OAuth 2 please.
Yes expanding the API with OAuth 2 would be awesome!
This is interesting, I'll have to do some research. Thanks for sharing.
Nice!
Great episode!
But there is a bug in lib/api_constrains.rb :
def initialize(options)
@verison = options[:version]
@default = options[:default]
end
Should it not be the following?:
@version = options[:version]
because in the matches method below it, you use the @version variable...
Oops, just saw David spotted it also ;)
I third/fourth that. OAuth2 security for your API please.
Each time you create a new MIME type name (
application/vnd.example.v1
,application/vnd.example.v2
, ...), a kitten is hurt! don't do that! that's bad!Use MIME parameters instead:
application/vnd.example; version=1
,application/vnd.example; version=2
, ... (version=
, orlevel=
, orv=
or whatever you want, this is part of your design).The semantic of a MIME type is that every document "flagged" with that type share the same "lineage", and that two different names are not related, even if they share a same prefix.
By incorporating a version identifier into the MIME type name, you are making the names distinct and are in the same case as if your V1 API was using
text/html
documents whereas your V2 now usesimage/png
pictures instead.Yes. I second that; adding security features.
And thanks for the cast Ryan :)
Awesome. Ryan, do you reckon Meteor is production ready at this time?
One thing I have started doing recently for a few APIs is to support versioning simply using folders with RABL templating. Depending on your situation, it can greatly reduce code duplication. Simply setup a single api controller and then render the corresponding template based on a version parameter i.e
render "#{params[:version]}/show"
and then create templates for each version (users/v1/show
,users/v2/show
). Since the controller between versions is typically largely unchanged in most cases, this may be an alternative approach. If anyone is curious for more details, perhaps I can add a guide to the RABL wiki.Really nice to see such presentation in RailsCasts. Even if little aside from Rails itself it's highly appreciated.
Following the same path, I'd love to see the same Raffler application made with EmberJS (formally SproutCore 2).
securing with OAuth2 please :)
thanks for the episode!
Great one. Super useful.
Just one comment: lib/api_constraints.rb has a typo at line 3 @verison instead of @version.
Nice one Ryan,
Would be good to expand this tutorial on how to secure your API with tokens or usernames and passwords? Also the possibility of using CanCan to authorize the api methods.
I would have it a guess the best place to start would be to create a api base class where most of that work could be done?
I really liked the page caching, because page serving is 100 times faster when using nginx compared to fragment caching and action caching. But I have some doubts, and I would really appreciate if you can answer these.
I have a large site and a lot of content like most read, recent content etc on almost each page. If i use page caching Do i delete all page cache like mentioned in this tutorial
If I use the above technique, I guess for users it will work fine but when Google will come to read the site, won't it take too long to read pages, because they might not be in cache at all that time.
If I use delayed jobs to generate page in cache in backend. Will that be a reasonable solution?
Any help will be really appreciated.
I'm just here to say, It's the year 2012 and i find this tutorial still useful, thanks Ryan! =D, I'm a student from Mexico and learning ruby on rails has become very easy thanks to your videos!
I hope you can keep doing videos for more years, thanks again and see ya ! =D
I'm just starting to look at rubber, but it looks like it's doing much of what I was building by hand. Can you share how you configured it to work with RDS?
The ending with Capybara is like a cherry on top. Such an awesome episode :)
That helped me too! Thanks for that.
Invocation of pygments.rb class methods within a Rails 3.2 app just kills the entire server process. Anyone here has any experience of this?
What's the difference in
cache('somekey') do ... end
andRails.cache.fetch('somekey') do ... end
? They seem fundamentally the same.This is really excellent stuff - definitely going to make use of this!
Awesome screencast!!!! very useful !!
Anyway, I wondering about how to setup a best
development / Production environment using Vagrant + puppet ?
Thanks
@nelsonkeating - see my response above.
You can definitely use for resources other than User. For instance, originally had User resource that included a bunch of additional information regarding the user's profile (address, age, phone #'s, etc.).
I decided that these attributes should be part of a different resource called RenterProfile (it's an app for renters), leaving nothing but the email address and password in the User resource. So I setup the appropriate controller, model, views and DB migration for this renter_profile resource. Once I had everything working (all the renter_profile fields within a single page/form, I then moved on to implementing a wizard for the renter_profile resource.
I followed Ryan's example pretty much verbatim simply swapping in renter_profile in place of user. I let my renter_profiles_controller perform the initial #create action with just a few basic fields (similar to creating the User with only the email and password). Then I created a renter_profile_steps controller (of course including the wicked gem same as Ryan's example). I placed the remaining attributes I wanted for the renter_profile into multiple form view files within the ~/views/renter_profile_steps directory.
The only hiccup I encountered was that
get "renter_profile/steps"
somehow ended up in my routes.rb file which messed everything up. Not sure how it ended up there (maybe wicked created it, but unlikely) or my coding partner did it without remembering... Regardless, with it removed, the renter_profile_steps_path began working correctly.You can see the actual code at: https://github.com/jvenator/wallet
We'll be taking the repository private in the next week or so as we start getting into more proprietary stuff, but for now feel free to have a look!
if still it is not working add
include ApplicationHelper
to your ApplicationController ;)same here. I've added that line in app controller but error is still on my page :
edit:
solved - just add that lines:
private
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
to the
app/helpers/application_helper.rb
;)Check out what sizing options come standard with bootstrap: http://twitter.github.com/bootstrap/base-css.html#forms
Add a CSS class to your form field, for example (using Simple Form):
<%= f.input :last_name, :input_html => { :class => 'input-medium' } %>
More info on using Simple Form: http://simple-form.plataformatec.com.br/#usage
If you're using Rails' Form_For, see the API: http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html
I'm using form_tag not form_for. I got the autocomplete working but when I submit the form, no parameters are passed. If I remove the javascript and submit the form, my inputs are passed as expected. Any ideas?
How does rubber handle adding an extra database instance? Does it automatically copy over the data and add itself as a slave?
Additionally, does the standard rubber config offer failover or would I need to add this in?
I am so confused. What is the difference between this and Cucumber?
This fix my Problem!
same for me , can anyone help?
There's a small typo in asciicast,
<% form_tag .... %> should have = in it.
ie
<%= form_tag ... %>
Else the button doesn't appear.
How do I adjust the width of the fields in Twitter bootstrap after scaffolding? Would be awesome if someone would be able to help me, thanks!
You can also use just one shared db connection as mentioned on:
platformatec-blog
I am building this functionality into my projects.
I would like to have the order of all the parent messages from new to old and the order of child messages from old to new.
Here is my code
<%= nested_microposts @microposts.arrange(:order => :created_at) %>
the code in model/message.rb seems to override .arrange(:order => :created_at)
So the order of all the messages is from new to old and the nested function doesn't work.
Can I arrange the order of all the messages as what I say??
Can anyone suggest an EC2 image to use?
I get this error as well when I run cap deploy:
* executing `deploy:check_revision' fatal: ambiguous argument 'origin/master': unknown revision or path not in the working tree. Use '--' to separate paths from revisions WARNING: HEAD is not the same as origin/master
but it's worked fine to call cap deploy:cold every time.
+1