RailsCasts Pro episodes are now free!

Learn more or hide this

Recent Comments

Avatar

I would love to know about validations, that's where I had difficulty. Particularly say if the task must be over 5 characters long, how do you show that error by inserting it dynamically into the original create form.

Avatar

how could i use "Devise.friendly_token" instead of leaving a blank password?

Avatar

This is what I came up with that seems to work:

_task.html.erb:

<%= formfor task do |f| %>
<%= f.check_box :complete, id: "task_complete
#{task.id}" %>
<%= f.submit "Update" %>
<%= f.label "complete_#{task.id}", task.name %>
<%= link_to "(remove)", task, method: :delete, data: {confirm: "Are you sure?"}, remote: true %>
<% end %>

Avatar

I keep getting this message for every request to webrick:

Started GET "/assets/jquery_ujs.js?body=1" for 127.0.0.1 at 2012-09-29 13:24:45 -0500
Served asset /jquery_ujs.js - 304 Not Modified (0ms)
[2012-09-29 13:24:45] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true

Does not seem to do any harm. Would anyone know what is it and how to get rid of the warning?

Bharat

Avatar

Is there an issue in _task.html.erb where clicking on the label element for each task checks/un-checks the completed box for the first task in the list, or did I miss something?

What's the best way to assign a unique name to the checkboxes for each task?

Avatar

That's been deprecated. Use .on() or .off() if you can.

Avatar

Thanks for the revision!

also check the .live method in jQuery. from the doc:

Attach an event handler for all elements which match the current selector, now and in the future.

so you can do something like

javascript
$('.edit_task').live('click', function ...
...
...
Avatar

+1

Awesome episode Ryan! Especially for a JS phobe like me!

Does anyone know of any good books that teach you how to use JS/jQuery/CS with Rails from scratch?

Avatar

I am having the same problem, but i'm using win7. I searched around and many people said it's impossible install therubyrace on win7, because the OS already comes with a Javascript Runtime Environment. Anyboby nows how can i install twitter_bootstrap gem on win7 ???

Avatar

Thanks for revising this. More episodes along these lines please.

Avatar

After my recent issue with document.getElementsByName in Internet Explorer, I am now a strong advocate of using jQuery whenever possible.

Avatar

Also, an interesting related talk from LA RubyConf about Rails, JQuery and Unobstrusive'ness.

Avatar

Great episode, thanks!
There is one more thing on jQuery i'd like to know about: why sometimes in development mode remote scripts executes twice (like double text_form submits) when 'requre tree .' is enabled?

Avatar

I made a typo, it should simply be:

SwingUtilities.invokeLater do
    HelloWorld.new
end
Avatar

Thanks for this Ryan! One thing I'd like to mention is that Swing components should always be initialized on the EDT (Event Dispatch Thread). So, instead of HelloWorld.new :

java_import javax.swing.SwingUtilities

...

SwingUtilities.invokeLater do |e|
    HelloWorld.new
end

This will prevent deadlocks and other unwanted behavior from happening.

Avatar

Could this work with nested form attributes? For example a Product model that has_many :images.

Avatar

Yes, but as usual, it's not 100% cross browser compatible. It is supported by Chrome, current versions of Firefox and the newest version of Safari (see https://github.com/blueimp/jQuery-File-Upload/wiki/Browser-support at the bottom of the page).

Avatar

I always have this error when I follow this tutorial:

OAuth2::Error: invalid_grant: The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.

when I'm in the phase of parsing token. What is the problem and how I can fix this ?

Avatar

Thanks for posting this. Very useul.

Avatar

There is only one thing that the gem covers in the example and the solution made from scratch doesn't cover: the relation for the tagging to belong to a user (act_as_tagger in the user model). How do you think this might be done, as most user authentication solutions (like Devise, Authlogic or Sorcery) doesn't provide the current_user helper in the ActiveRecord layer.

Avatar

I love this railscast. I have had to make some changes and such to the unicorn configurations to work with my platform, but overall it works well. Nice starting point.

Avatar

So i'm having a weird issue - followed the instructions to the tee on a new EC2 instance running Ubuntu 12.04 (only wrinkle was in the rbenv install process, found a good tutorial explaining the differences here: http://www.stehem.net/2012/05/08/how-to-install-ruby-with-rbenv-on-ubuntu-12-04.html

So i THINK i'm in good shape! UNTIL I try to cap deploy: the connection hangs AFTER connecting successfully..?! Turned on SSH logging, and the key exchange is successful, but then the script doesn't continue. I CAN login without a password from the terminal, so I know my key is set up correctly on my deployer user.

It's all a little odd.

Avatar

If you have to setup vagrant on windows (for whatever reason), I recommend to install chocolatey and then install vagrant with:

cinst Vagrant.install

This downloads and install putty, virtualbox and vagrant in place.
This way I setuped a machine for our frontend developer.

Avatar

I am having problem installing the twitter-bootstrap-rails gem. I searched around online and coulnd't find a solution. Here is the error message:

Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.

    /Users/lionel_lei/.rvm/rubies/ruby-1.9.3-p194/bin/ruby extconf.rb 

checking for main() in -lobjc... yes
creating Makefile

make
compiling rr.cpp
make: clang++: No such file or directory
make: *** [rr.o] Error 1

Gem files will remain installed in /Users/lionel_lei/.rvm/gems/ruby-1.9.3-p194/gems/therubyracer-0.10.2 for inspection.
Results logged to /Users/lionel_lei/.rvm/gems/ruby-1.9.3-p194/gems/therubyracer-0.10.2/ext/v8/gem_make.out
An error occured while installing therubyracer (0.10.2), and Bundler cannot continue.
Make sure that gem install therubyracer -v '0.10.2' succeeds before bundling.

I am on OSX Lion and have xcode 4.5 installed.

Anyone here have any suggestions? Appreciate it!

Avatar

Even more optimization: use pluck to get ids:

ruby
def self.up
  add_column :projects, :tasks_count, :integer, :default => 0

  Project.reset_column_information
  Project.pluck(:id).each do |p_id|
    Project.reset_counters p_id, :tasks
  end
end

def self.down
  remove_column :projects, :tasks_count
end
Avatar

Is there any way to use jQuery to filter items that are on next page or subsequent pages before you have scrolled to them? The use case would be a view of thumbnails that the user can scroll through with a list of tags above them that the user could use to narrow down the set of results. The problem I am having is not being able to return the correct results if the user has not scrolled down the page.

Avatar

register_template_handle accepts a glob of extensions, so instead of registering each template extension like:

ruby
ActionView::Template.register_template_handler(:md, MarkdownTemplateHandler)
ActionView::Template.register_template_handler(:markdown, MarkdownTemplateHandler)

you can do:

ruby
ActionView::Template.register_template_handler(:md, :markdown, MarkdownTemplateHandler)
Avatar

Great episode thx a lot.
I noticed something strange though. you create thumbnails based on the presence of the key attribute in the Painting class on the after_save

ruby
  def enqueue_image
    ImageWorker.perform_async(id, key) if key.present?
  end

but then you also set the key attribute in the perform method of the background task

ruby
    def perform(id, key)
      painting = Painting.find(id)
      painting.key = key #setting the key again
      painting.remote_image_url = painting.image.direct_fog_url(with_path: true)
      painting.save! # enqueue_image will get called again
      painting.update_column(:image_processed, true)
    end

I think this will result in putting another message in the background queue. which will always keep your worker busy recreating thumbnails. Am I correct?

Avatar

First check if your private key is in ~/.ec2 directory.
After, try to remove the .pem extension from your private key file.

Avatar

First check if your private key is in ~/.ec2 directory.
After, try to remove the .pem extension from your private key file.

Avatar

Great cast Ryan! I used FOG recently via the Ruby Backup gem - to keep DB backups on S3, as well as a few different mirrors for user uploads. Great gem! Thanks again for the cast.

Avatar

If you just want to resend the activation email, then you can add a method to your user model which calls the protected send_activation_needed_email! method. This sends the email again.

ruby
def resend_activation_email!
  send_activation_needed_email!
end
Avatar

Probably because the carrierwave_directgem (and Amazon S3 itself), doesn't support uploading multiple files in a single POST request. You need some kind of client-side scripting to separate the files into individual POST requests and insert the other form fields (key, policy, signature etc.) on the fly each time.

The final example still uses Carrierwave though, just not for the upload. The jQuery plugin uploads the file straight to S3. Then, in the done callback, the URL of the uploaded file gets "calculated" and POST-ed to the paintings#create action. The URL comes back in the response header from S3 (as "location" I think), so you could probably get it from there if you wanted.

In the paintings#create action, things start to look normal again. Either in the app, or a worker process, the record gets created and Carrierwave copies the raw file from the S3 bucket, to the location where your Carrierwave settings want it to be, then runs any image processing you have set up.

BTW, having a separate bucket for holding the raw uploads from the jQuery plugin is probably a good idea if you're not persisting the record before letting the user upload. You can end up with files that never get associated to anything in the database.

Let Carrierwave copy each file that gets associated to a record and process it. Carrierwave won't delete the raw upload file, but you can use the aws-sdk gem to delete it when Carrierwave finishes working. Finally, set up a task to periodically clear out old files in the "raw upload bucket" and that should take care of cleanup.

For that last part, you might want to prepend a timestamp to the SecureRandom portion of the key, then use the prefix method in aws-sdk, so you can do something like raw_uploads_bucket.objects_with_prefix('20120926').delete_all, to delete all the raw uploads from yesterday. Might be a good idea to check that all those workers are finished running too.

If it works for your UX though, persisting the record before letting the user upload makes cleanup a bit simpler.

Avatar

Thanks Ryan for that Railscast !
I also get troubles trying to make it work with cancan.
hackeron, did you manage to use the cancan_strong_parameters gem ?
I miss an enhanced doc on it ( You see what I mean ;-) )

Avatar

Great screencast. I made an example app that uses http://blueimp.github.com/jQuery-File-Upload/ to upload straight to S3. It was using a rather complex iframe trick to get around Amazons same origin policy. That was before Amazon introduced CORS, now my app is basically obsolete... ;-)

Ryan, will you make a gem from the multifile uploader you showed in the end? I think that'd be a great idea.

Avatar

Great episode.

Can you please add in the show notes some of the libraries to process images client-side. It would be helpful! :)

Avatar

Great episode. Can you explain what motivated you to build the final example without fog or carrierwave?

Avatar

Same here. The USR2 signal or quit process isn't acting as expected...

Avatar

To complete the full circle, it would be great to see how to use tags with http://aehlke.github.com/tag-it/

Avatar

Anyone know how I might update the position number in the view when the user drops the element? Right now, everything is working but the numbers I have showing do not update to show their new position. It's probably basic ajax stuff, any ideas?

Avatar

I also have this problem. And i can't seem to find out how this is fixed

My code:

ruby
class AuthenticationsController < ApplicationController
  
  def index
    @authentications = current_user.authentications if current_user
  end
  
  def create
    omniauth = request.env["omniauth.auth"]
    authentication = Authentication.where(:provider => omniauth['provider'], :uid => omniauth['uid']).first

    if authentication && defined? authentication.user
  
      flash[:notice] = "Signed in successfully."
      sign_in_and_redirect(:user, authentication.user)
  
    elsif current_user
  
      current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => omniauth['credentials']['token'] )
      flash[:notice] = "Authentication successful."
      redirect_to authentications_url
  
    else
  
      user = User.new
      user.apply_omniauth(omniauth)

      if user.save
        flash[:notice] = "Signed in successfully."
        sign_in_and_redirect(:user, user)
      else
        session[:omniauth] = omniauth.except('extra')
        redirect_to new_user_registration_url
      end
  
    end
  
  end

  protected
  
  # This is necessary since Rails 3.0.4
  # See https://github.com/intridea/omniauth/issues/185
  # and http://www.arailsdemo.com/posts/44
  def handle_unverified_request
    true
  end

end