RailsCasts Pro episodes are now free!

Learn more or hide this

Recent Comments

Avatar

Would be awesome to see how to create our own 'folder', and how to see files be placed inside of folders.

I have already achieved the same effect from this video on my own a few months ago with jQuery File Upload, and I was still interested on how to see some type of folder abstraction integrated alongside.

( And i don't mean uploading a folder. I mean you can create a Folder object, which has files on the inside, so it follows some sort of directory managing)

Avatar

Hi Erik, the inverse_of didn't work. The fileupload method is being used on the form of a parent resource. When I choose the files (multiple nested img resource) and upload it, a parent resource is being created as many times as files uploded with only one pic in it, instead of one parent with many pics.

Avatar

Hi, How would you implement this with a nested resource. For example I have a form for a item with nested pictures. How can I implement the fileupload() method to the items form?

Thanks!

Avatar

I got it to work with tables by using this structure:

ruby
%table#sortable_table
  %thead
    %tr
      %th 
      %th Title
      %th Description
      %th Order
  %tbody{"data-update-url" => sort_featured_items_url}
    - @featured_items.each do |featured_item|
      =content_tag_for :tr, featured_item do
        %td
          = image_tag "shared/drag_handle.png", :alt => "Drag", :class => "handle"
        %td= featured_item.title
        %td= featured_item.description
        %td= featured_item.order

So basically you wrap your headers into a %thead tag and your other rows with a %tbody tag.

ruby
The JS then looks like this:
$("#sortable_table tbody").sortable({
        axis:'y',
        handle: '.handle',
        update: function(){
          $.post($(this).data('update-url'), $(this).sortable('serialize'));
        }
});
  });
Avatar

Nevermind, the thread above that started by "Coda" answered this.

Avatar

Fantastic, as always!

I note, however, that the user is always redirect to the root_url, which isn't always ideal.

Which is the best method for redirecting a user to the "original" page after they have (possibly unsuccessfully) logged in?

This should also cover static pages - for example, if the user is on an "About" page, then logs in, they should be returned to the "About" page.

Thanks!

Avatar

I just dealt with this recently. I used resumable.js to handle the client side and then processed each chunk as it's own upload then assembled the file on the server once the file was completed. If you email me at matt at thinkific dot com I can give you some more details.

Avatar

Hey Ryan,

Thanks for the great screencast! The solution that I found to your problem with slow rank or weighted search on multiple columns is to create a column to actually use for searching:

Example:

ruby
class AddIndexForFullTextSearch < ActiveRecord::Migration
  def up
    execute "ALTER TABLE users ADD COLUMN tsv tsvector"
    execute <<-QUERY
    UPDATE users SET tsv = (to_tsvector('english', coalesce("building"."first_name"::text, '')) || 
                            to_tsvector('english', coalesce("building"."last_name"::text, '')));
    QUERY
    
    execute "CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
              ON users FOR EACH ROW EXECUTE PROCEDURE
              tsvector_update_trigger(tsv, 'pg_catalog.english', first_name, last_name);"
  end
  def down
    execute "drop trigger tsvectorupdate on users"
    execute "alter table users drop column tsv"
  end
ruby
class User < ActiveRecord::Base
  include PgSearch
  pg_search_scope :search, against: [:first_name, :last_name], 
    using: {
      tsearch: {
        dictionary: "english",
        tsvector_column: 'tsv'
      }
    }
end

I've tested this solution with 200K records and it makes a significant difference.
Solution was found on "http://linuxgazette.net/164/sephton.html"

Avatar

Hey I'm using the same code to dynamically add fields too! How did you handle the order position for multiple new fields?

Avatar

Nested forms for polymorphic associations are messy.

If the relationship wasn't polymorphic, you could do inverse_of on each model so that the code knew the relationship of the objects in memory. http://guides.rubyonrails.org/association_basics.html#bi-directional-associations

I ran into this issue and did a sort-of hack to avoid validation errors in a nested polymorphic form: https://gist.github.com/1936811

Avatar

the stream class method has been removed

see this issue

and from rails api docs

Notice that :stream only works with templates. Rendering :json or :xml with :stream won’t work.

:(

Avatar

Thanks for great episode, Ryan. I've been struggling with this library, trying to integrate it with Rails, but there were no docs and examples were too messy to understand.

I wonder, is it possible to use jQueryFileUpload in a "new" action of a controller with many nested pictures (good if it would even work with polymorphic associations)?Because, to create a picture under a gallery, it is required to have an id of a parent.. but in a new action a parent is not persisted in db yet and has no id.

A workaround for me was to create a parent model and to put a condition to use file upload only on "edit" action. I also masked "edit" link to "add pictures or edit" for users :-) But, I believe, there are better solutions. Any ideas?

Avatar

I prefere Earle Clubbs method. Besides turn off cache classes when you are using spork with guard.

http://www.avenue80.com/tiny-tip-spork-not-reloading-classes/

pengpenglin's method didnt work quite well with model validations and cache counters.

Avatar

Thanks so much.. i was having anxiety attack with massive codebase thinking about re-adding all those as new methods :S

Avatar

Well, both of those return an empty array. I guess this is because it is looking for tags that match both conditions (which is impossible since the name attribute is unique), instead of looking for posts that have both the tags.

Anyway thank you for pointing me to arel_table, I'll have a deeper look on that to see if it is what I need.

Avatar

Props on keeping your cool. I do terrible in those situations.

Avatar

https://github.com/rails/arel/blob/master/lib/arel/predications.rb

ruby
tag = Tag.arel_table
Article.joins(:tags).where(tag[:name].in_all(["foo", "bar"]))

or maybe

ruby
tag = Tag.arel_table
Article.joins(:tags).where(tag[:name].matches_all(["foo", "bar"]))
Avatar

The idea of the keys is to limit the access only to the API. So in that case you can still log in to Twitter and reset your application keys.

Avatar

@Patrick, that actually gives me the same result.

Let me explain with better words what I'm trying to achieve:

post1 has tags "foo, bar, baz"
post2 has tags "foo, bar"
post3 has tags "foo, baz"

I need to a query that passing "foo, baz" returns only post1 and post3, since they are the only posts to have both foo and baz.

Thank you for your help.

Avatar

i have an existing app with sqlite database and i want to create a new app only for active admin.
can i use the database from the first app?
if yes, can you show me how to do it?

Avatar

You should use arel_table.

ruby
tag = Tag.arel_table
Article.joins(:tags).where(tag[:name].in(["foo", "bar"]))
Avatar

What if I want to query for articles that belong to multiple tags?

I tried this method:

ruby
Article.joins(:tags).where(:tags => { :name => ["foo", "bar"] } )

but this returns me every post that has either tag foo, or bar or both.

How do I search only for posts that have both foo and bar at the same time?

Avatar
ruby
article.tags.map(&:name).map { |t| link_to t, tag_path(t) }.join(', ')

should really be

ruby
article.tags.map { |t| link_to t.name, tag_path(t.name) }.join(', ')

The original code will produce unnecessary iterations that might start to affect performance once the number of tags increases. In general: Keep iterations to a minimum – in my experience, it's the number one performance problem of most Rails apps.

Avatar

Nevermind, in my case it was:

ruby
resources :featured_items do
  collection do
    post "sort"
  end
end
Avatar

Looks like the new version of the slim gem broke the monitoring sinatra app:
https://github.com/mperham/sidekiq/issues/411

Adding this to your gem file will fix it:
gem 'slim', '<= 1.3.0'

Just wanted to help others avoid the frustration until the docs are updated!

Avatar

Very nice. I have to mention that PDFKit is also used to generate pdf files from html strings as follows:

html = "< h1>pla pla pla< /h1>"
kit = PDFKit.new(html, :page_size => 'Letter')
pdf = kit.to_pdf
file = kit.to_file("path/to/pdf/with/pdf_name.pdf")

Note: this might throw an error of missing wkhtmltopdf even when you unstall wkhtmltopdf, and I found out that you still need to install ghostscript to you computer (mine is Mac 10.7.4).

Avatar

Thanks for the update. Can you show me what the routes look like with ruby 1.8.7? I can't seem to get mine working.

Avatar

The code from the article is the Rails 3.2+ compliant version of the replacement you supplied. They do the exact same thing but your version wont work in Rails 4.1

Avatar

You probably want to replace

ruby
max = tags.sort_by(&:count).last

with

ruby
max = tags.max_by(&:count)

There's no need to sort the array only to pick the largest element.

Avatar

I use jqPlot in a project at work and so far I like it. It does have somethings which may be hard to implement. However you can use the gem I wrote plot simple(documentation) to get around this.

Avatar

Yeah, same here, @Eric_Berry, please post the details!

Avatar

Check out Locomotive CMS overview in my blog - http://railsguides.net/2012/09/24/the-best-content-management-system-cms . Locomotive CMS is the best system for today in my opinion

Avatar

Ryan used Ruby 1.9 hash syntax, that's why. You seem to be on Ruby 1.8x?

Avatar

Such an awesome episode. Though to get this example to work, I had to adjust the syntax from line 2 of your routes.rb example from:

ruby
puts "get 'tags/:tag', to: 'articles#index', as: :tag"

to

ruby
puts "get 'tags/:tag' => 'articles#index', :as => :tag"
Avatar

I didn't see your comment before I posted mine. I don't remember everything I did, but counter_cache was probably the single biggest improvement. I also recall using memcached for storing certain results.

That said, I was doing some pretty unnecessary tag stuff. It was possible to create queries of tags with logical and, or, and not operators. Features that ultimately went mostly unused.

Avatar

Hi Ryan,

Awesome info. Two questions:

  1. Wouldn't it be better to call the delay method from within the Newsletter model (or use handle_asynchronously)? That way the background functionality can be encapsulated into the Newsletter model and away from the controller. Better if we need to change it later...?

  2. It seems to me that the big difference between serializing the object and just saving the ID is the state of the object. If you serialize it, then you are capturing the state when the delay method is called. If you just save the ID, then it will use the state of the object when the Newsletter is delivered.
    I imagine that one or the other would be desirable, depending on the details of the application.

Avatar

How did you implement the caching? In the comment above I suggested using a counter_cache.

Avatar

Just digging into Koala and using it to create feed posts to a page. I can successfully create a post with the below, but struggling to make the update work.

INSERT CODE SNIPPET - Works great and returns post id from fb

ruby
@page_graph.put_connections(current_tenant.fbpage_id, 'feed', 
                        :message => @post.caption,
                        :caption => @post.caption,
                        :description => @post.description, 
                        :name => @post.title,
                        :link => url_for(@post),
                        :picture => '2B(1).jpg'
                        
                        )

UPDATE CODE SNIPPET - fb returns true, but not reflecting updates on fb page when refreshed

ruby
@page_graph.put_object(@post.uid, 'feed', 
                        :message => @post.caption,
                        :caption => @post.caption,
                        :description => @post.description, 
                        :name => @post.title,
                        :link => url_for(@post),
                        :picture => 'h2B(1).jpg'
                        
                        )

Any thoughts on where I'm going wrong?

  • thanks
Avatar

I implemented my own tagging system similar to the code you wrote a while back, but I noticed that it did not scale well. If you only have a few tags it works fine, but if you have hundreds of thousands or millions and similar numbers of articles then performance degrades substantially. I ended up having to do quite a bit of caching to get acceptable performance, especially for the tag cloud.

I did not use, or know about, the acts_as_taggable_on gem at the time. Does anybody know how well it scales? If not I will definitely be running some performance tests on it this week.

Avatar

Assuming that a tag should only be created once (unique constraint on name) I'd rather use:

ruby
self.tags = names.split(",").map do |n|
  Tag.find_or_create_by_name(n.strip)
end

instead of

ruby
self.tags = names.split(",").map do |n|
  Tag.where(name: n.strip).first_or_create!
end

For better performance one should also consider a counter cache on the belongs_to :tags in the taggings model. This would avoid the join when calculating the tag counts in:

ruby
def self.tag_counts
  Tag.select("tags.*, count(taggings.tag_id) as count").
    joins(:taggings).group("taggings.tag_id")
end
Avatar

I think link_to ensures that?

Avatar

I like this one even more.

Why is CoffeeScript so popular these days?

I figured out how jQuery works and now I have to start over and learn Coffeescript :-(

Avatar

Great tutorial, Ryan!

I was lucky enough to get this working on my machine.

The only problem I have is that the nested attributes are not saved to the database in the order in which I created them.

E.g. sometimes I create 3 answers at once, then click "Update" and the answers do appear on the form, but not in the correct order. I can't see any pattern in there, so I assume that they get saved to the database randomly.

Is there any way to fix this?

Avatar

Shouldn't the assignment of self.tags in the method tag_names= be moved to an after_save callback method? What if the validations on a newly created article fail? The tags would still be created without proper referencing.