RailsCasts Pro episodes are now free!

Learn more or hide this

Recent Comments

Avatar

I recently looked into Grails and liked the service object approach. May I ask - which framework do you prefer at this point? (Apologies for this being off topic)

Avatar

This seems highly insecure, what if I simply in spec your page in my browser and alter the html?

I suppose you would be validating credentials in controllers as well though...

On the other hand what if it's secure data? Are there not valid cases where the HTML should never be delivered for a subset of users?

Avatar

Yeah, I've figured that out, but it would be nice to know why Ryan didn't have to do that. Is there a better way?

Avatar

I had the same problem and the solution is basically that you have to enable hstore on the database. Run the following (after you have created the db of course :)

$> psql blog_development

blog_development=# CREATE EXTENSION hstore;

For futher information and how to do this as a rails migration see this

Avatar

I get that from simply doing an rake db:migrate on development with an hstore type :(

Avatar

How do we go about having redis automatically update caching (development and production) if new products are being added on a regular basis without running

ruby
rake search_suggestions:index

each time a new record is being added in the database?!!

Avatar

Help me not working method voted for? After the user has voted

Avatar

config.active_record.schema_format = :sql

helped to run minitest with hstore

Avatar

Got bug when using #120 Thinking Sphinx and models what include concerns like in #398-service-objects

card.rb

ruby
# coding: utf-8
class Card < ActiveRecord::Base
  include Userable

  ...
  #Sphinx search
    define_index do
      indexes :name
      indexes :text
      has :card_way_id, :card_type_id, :card_mode_id
      set_property :delta => true
    end 
end

concerns/userable.rb

ruby
module Userable
  extend ActiveSupport::Concern

  included do
    attr_accessible :user_id

    belongs_to :user
        
    validates :user_id, presence: true
    validates :user_id, numericality: { only_integer: true },
                        if: lambda{|m| !m.user_id.nil? }
  end
end
ruby
Warning: Error loading /home/roma/rails/discount/app/models/concerns/userable.rb:
uninitialized constant Concerns::Userable
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/activesupport-3.2.9/lib/active_support/inflector/methods.rb:230:in `block in constantize'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/activesupport-3.2.9/lib/active_support/inflector/methods.rb:229:in `each'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/activesupport-3.2.9/lib/active_support/inflector/methods.rb:229:in `constantize'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/activesupport-3.2.9/lib/active_support/core_ext/string/inflections.rb:54:in `constantize'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/context.rb:64:in `block (2 levels) in load_models'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/context.rb:54:in `each'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/context.rb:54:in `block in load_models'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/context.rb:53:in `each'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/context.rb:53:in `load_models'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/context.rb:15:in `prepare'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx.rb:81:in `block in context'
<internal:prelude>:10:in `synchronize'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx.rb:78:in `context'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/active_record.rb:166:in `define_index'
/home/roma/rails/discount/app/models/card.rb:40:in `<class:Card>'
/home/roma/rails/discount/app/models/card.rb:2:in `<top (required)>'
(irb):1:in `irb_binding'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/workspace.rb:80:in `eval'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/workspace.rb:80:in `evaluate'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/context.rb:254:in `evaluate'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:159:in `block (2 levels) in eval_input'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:273:in `signal_status'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:156:in `block in eval_input'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:243:in `block (2 levels) in each_top_level_statement'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `loop'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `block in each_top_level_statement'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `catch'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `each_top_level_statement'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:155:in `eval_input'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:70:in `block in start'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:69:in `catch'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:69:in `start'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/railties-3.2.9/lib/rails/commands/console.rb:47:in `start'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/railties-3.2.9/lib/rails/commands/console.rb:8:in `start'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/railties-3.2.9/lib/rails/commands.rb:41:in `<top (required)>'
script/rails:6:in `require'
script/rails:6:in `<main>'
Avatar

Got bug when using #120 Thinking Sphinx and models what include concerns like in #398-service-objects

card.rb

ruby
# coding: utf-8
class Card < ActiveRecord::Base
  include Userable

  ...
  #Sphinx search
    define_index do
      indexes :name
      indexes :text
      has :card_way_id, :card_type_id, :card_mode_id
      set_property :delta => true
    end 
end

concerns/userable.rb

ruby
module Userable
  extend ActiveSupport::Concern

  included do
    attr_accessible :user_id

    belongs_to :user
        
    validates :user_id, presence: true
    validates :user_id, numericality: { only_integer: true },
                        if: lambda{|m| !m.user_id.nil? }
  end
end
ruby
Warning: Error loading /home/roma/rails/discount/app/models/concerns/userable.rb:
uninitialized constant Concerns::Userable
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/activesupport-3.2.9/lib/active_support/inflector/methods.rb:230:in `block in constantize'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/activesupport-3.2.9/lib/active_support/inflector/methods.rb:229:in `each'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/activesupport-3.2.9/lib/active_support/inflector/methods.rb:229:in `constantize'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/activesupport-3.2.9/lib/active_support/core_ext/string/inflections.rb:54:in `constantize'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/context.rb:64:in `block (2 levels) in load_models'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/context.rb:54:in `each'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/context.rb:54:in `block in load_models'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/context.rb:53:in `each'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/context.rb:53:in `load_models'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/context.rb:15:in `prepare'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx.rb:81:in `block in context'
<internal:prelude>:10:in `synchronize'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx.rb:78:in `context'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/thinking-sphinx-2.0.13/lib/thinking_sphinx/active_record.rb:166:in `define_index'
/home/roma/rails/discount/app/models/card.rb:40:in `<class:Card>'
/home/roma/rails/discount/app/models/card.rb:2:in `<top (required)>'
(irb):1:in `irb_binding'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/workspace.rb:80:in `eval'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/workspace.rb:80:in `evaluate'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/context.rb:254:in `evaluate'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:159:in `block (2 levels) in eval_input'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:273:in `signal_status'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:156:in `block in eval_input'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:243:in `block (2 levels) in each_top_level_statement'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `loop'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `block in each_top_level_statement'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `catch'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `each_top_level_statement'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:155:in `eval_input'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:70:in `block in start'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:69:in `catch'
/home/roma/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/irb.rb:69:in `start'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/railties-3.2.9/lib/rails/commands/console.rb:47:in `start'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/railties-3.2.9/lib/rails/commands/console.rb:8:in `start'
/home/roma/.rvm/gems/ruby-1.9.3-p194/gems/railties-3.2.9/lib/rails/commands.rb:41:in `<top (required)>'
script/rails:6:in `require'
script/rails:6:in `<main>'
Avatar

thanks Ryan!
i will learn ember.js :)

btw, anyone having this?

$ rake db:test:prepare

rake aborted!
PG::Error: ERROR: type "hstore" does not exist
LINE 1: ...te, "tags" character varying(255)[], "properties" hstore, "c...

Avatar

Thank you Ryan, I am very excited about Rails 4 and can't wait for it to hit at least pre release.

With all these changes under the hood do you expect it to be tough switching from Rails 3? Or the transitions this time should be smoother than from Rails 2.x to 3.x?

Avatar

PG::Error: ERROR: type "hstore" does not exist is the exact error.

Avatar

I tried following along but I'm having problems with hstore. I've upgraded to the latest version of postgres with homebrew, but rake db:migrate complains about hstore not being a valid type...

Avatar

disposition: "inline" isn't working in Chrome for me. This appears to be somewhat of a known problem with Chrome, something related to Chrome not knowing the file type and deciding not to render it. It works fine in Firefox. Does anybody know a fix?

Update: removing the Mime configuration line seemed to fix this problem. This is using Rails 3.2.1.

Avatar

Just in case someone is interested to know, in Ubuntu versions 11.10 (Oneiric Ocelot) and onwards the "admin" group is not going to be provided by default. The power that be are favouring the "sudo" group instead of "admin" group. If you're upgrading from a lower version, your "admin" group will persist but on a fresh install "admin" group will be missing.

So if you get an error that "admin" group does not exist, simply replace it with "sudo".

adduser deployer --ingroup sudo

Credits to Aditya Sanghi, here: http://railscasts.com/episodes/337-capistrano-recipes?view=comments#comment_157369

Avatar

If you have really large site (maybe some SaaS system), then you probably like my wiselinks gem.

You may find it similar to PJAX, but it is as easy to use as Turbolinks (I mean, easy to start) and as configurable as PJAX.

Avatar

I love both approaches. I relate well to Gary's DAS site because I've used Unix, Vim, and other scripting languages for a really long time, and am especially interested in how to improve my workflow using those tools. However, your approach is usually just what I need to get started using a new gem or technique for my Rails projects.

I greatly appreciate you spending more time on Refactoring, though, especially with a more Ruby or OO-centric approach. It has become the central theme at my work, where we've had enormous technical debt accrue over a 2 year period. IMHO, the traditional approach that many developers have learned initially for Rails is the root cause of why many codebases have grown to a barely maintainable level. Anything you can do to help developers learn better habits and produce more readable, elegant and stable code will certainly pay huge dividends when others inherit projects.

Please continue this work, if not for the free RailsCasts side, at least for the Pro subscribers.

Thank you for all of your hard work!

Avatar

Tip: I had to restart my rails server after I added the "require" lines to the CSS and javascript files. Rails was throwing an error that it could not find those files until I did this.

Avatar

This was a really awesome episode. Starting with a bare bones app and plugging in modules when I need them makes more sense to me than starting with everything but the kitchen sink then pulling out (in a sort of error-proned way) what I don't need. I am new to Rails and I was curious why Rails has --skip-[module name] options when creating a new app rather than --include-[module name] options. Now I understand why I've seen discussions on some blogs about Rails becoming too "big". Now I know (thanks to this episode) that's not the case; Rails is just delivered that way.

Avatar

The article Ryan linked to might shed some light. It gives an overview of all the different strategies for dealing with fat models (including Service Objects and Decorators).

http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

Avatar

I m trying to use this gem and run into some issues. I managed to get around most of them, but now I am getting a seg fault. I believe it is happening in the controller where I have this code

from [based on material from here](https://github.com/berk/will_filter)
@regions = Region.filter(:params => params)

``` here is the seg fault message I am getting

/home/danny/.rvm/gems/ruby-1.9.3-p362/gems/activerecord-3.2.9/lib/active_record/relation.rb:241: [BUG] Segmentation fault
ruby 1.9.3p362 (2012-12-25 revision 38607) [i686-linux]

-- Control frame information -----------------------------------------------
c:0186 p:0018 s:0821 b:0818 l:000817 d:000817 METHOD /home/danny/.rvm/gems/ruby-1.9.3-p362/gems/activerecord-3.2.9/lib/active_record/relation.rb:241
c:0185 p:0028 s:0815 b:0815 l:000814 d:000814 METHOD /home/danny/.rvm/gems/ruby-1.9.3-p362/gems/activerecord-3.2.9/lib/active_record/scoping/default.rb:41
c:0184 p:0024 s:0812 b:0812 l:001934 d:000811 LAMBDA /home/danny/.rvm/gems/ruby-1.9.3-p362/gems/activerecord-3.2.9/lib/active_record/scoping/named.rb:180
c:0183 p:---- s:0807 b:0807 l:000806 d:000806 FINISH
c:0182 p:0022 s:0805 b:0805 l:0020c8 d:000804 BLOCK /home/danny/.rvm/gems/ruby-1.9.3-p362/gems/activerecord-3.2.9/lib/active_record/relation/delegation.rb:37
c:0181 p:0007 s:0803 b:0803 l:002134 d:000802 BLOCK /home/danny/.rvm/gems/ruby-1.9.3-p362/gems/activerecord-3.2.9/lib/active_record/relation.rb:241
c:0180 p:0396 s:0801 b:0801 l:000800 d:000800 METHOD /home/danny/.rvm/gems/ruby-1.9.3-p362/gems/activerecord-3.2.9/lib/active_record/scoping.rb:98
c:0179 p:0018 s:0792 b:0792 l:002134 d:002134 METHOD /home/danny/.rvm/gems/ruby-1.9.3-p362/gems/activerecord-3.2.9/lib/active_record/relation.rb:241
c:0178 p:0055 s:0789 b:0789 l:0020c8 d:0020c8 METHOD /home/danny/.rvm/gems/ruby-1.9.3-p362/gems/activerecord-3.2.9/lib/active_record/relation/delegation.rb:37
c:0177 p:---- s:0783 b:0783 l:000782 d:000782 FINISH
c:0176 p:0163 s:0781 b:0781 l:000780 d:000780 METHOD /home/danny/.rvm/gems/ruby-1.9.3-p362/gems/will_filter-3.1.9/app/models/will_filter/filter.rb:821
c:0175 p:0250 s:0777 b:0777 l:000776 d:000776 METHOD /home/danny/.rvm/gems/ruby-1.9.3-p362/gems/will_filter-3.1.9/lib/will_filter/extensions/active_record_extension.rb:45

-- C level backtrace information -------------------------------------------

Avatar

we need to add the following like of code:

ActsAsTaggableOn.force_parameterize = true

Avatar

Makes more sense after reading this:
http://rubysource.com/rails-4-quick-look-strong-parameters/

Some of repetition that I fear when I see code like this:


def book_params
if current_user && current_user.admin?
params[:book].permit(:name, :author, :public)
else
params[:book].permit(:name, :author)
end
end

Can be reduced be creating constant (named by role?) within the class:

def book_params
if current_user && current_user.admin?
params[:book].permit(User.attrbutes_assignable_by_admin)
else
params[:book].permit(User.attrbutes_assignable_by_non_admin)
end
end
`

And though I understand that this a better placement of state logic, still seems a bit cumbersome.

The whitelist lets me say all the attributes that are permitted unless a specific role was in use. It isn't often, but when it is, it's explicit. This forces me to specify the user role every place I'm acting on an attribute via a controller. And with the increase in times I have to remember to do something the more times I'm likely to miss something an create a security hole.

Again, I'm happy to be enlightened.

Avatar

Thanks for sharing that...solved the issue I was having this evening without having to spend a lot of time searching.

Avatar

You make the changes in big releases easy to understand, thanks!

What I don't quite understand is the move of protected attributes from the model to the controller:

  • Doesn't that assume you're only going to be using one controller to update a give type of model, else you'll have to repeat your code (like in an admin controller)?
  • Wouldn't this change make controllers fatter and models skinnier (the opposite direction we push for)?

There's probably something I'm missing, so if someone could enlighten me then I'd be grateful.

Avatar

How does a Service Object differs from a Decorator ?

Avatar

Hi Ryan! Do you feel that there is any discernable cost to getting started writing a new Rails 4 application now and updating it as opposed to waiting for the release? My concerns wouldn't involve many gems. I'm thinking more along the lines of application structure, features getting dropped, or things like that.

Avatar

Perfect! This was exactly what I am needing - the blog-post/calendar display at the end.

Avatar

I find it difficult to setup the server,so I want to see your amazing blog~
But I can't open the link above.
Can you send the link or your article to me?
my email adress: dqaria gmail.com
Thank you!

Avatar

Wonderful cast! I used roo to import some legency-excel data. Exporting excel is useful in rails application.

Thanks a lot!

Avatar

I am having problems to use CanCan's accessible_by method. If you have the time please take a look at this Stackoverflow question: http://stackoverflow.com/questions/14138408/cancan-accessibly-by-returns-different-responses-in-spec-and-controller

Avatar

If, like me, you also use Ryan's awesome nested_form gem, then you will be very interested in Issue #145 where the compatibilities with Turbolinks are getting resolved

Avatar

Nice gravedigging ;)

As of Rails 3.2 plugins are deprecated. Also this is a very old episode and restful_authentication itself hasn't been updated for more than a year.

Consider following some newer episodes on authentication. You could try asking Ryan for a revisit, but I doubt it'd be high on his list.

Avatar

Erich, that looks pretty nice. Perhaps your pattern is a good way to DRY up code between two PushState frameworks (Turbolinks on Desktop / jQuery Mobile on Mobile)

Avatar

+1

This fixed problems I was having with the template not rendering with the object.

Avatar

For those that are interested "modularizing" their CoffeeScript for easy loading in Turbolinks and Pjax environments I'd appreciate comments on https://github.com/erichmenge/handlers-js#readme. It works out of the box with Turbolinks and is a pattern I've used with great success.

Avatar

nice approach rayn ,,I didnot test it in production yet ,,but it seems that its not working with with Endless page approach you showed before .

Avatar

Hello,
I am using Rails 3.
script/plugin install git://github.com/technoweenie/restful-authentication.git doesnt seem to work for me.

-bash: script/plugin: No such file or directory
is the error that i get from that command. Anyone, please rectify the error going on/

Avatar

Super awesome... This solves my varying nested level polymorphic nightmare. It took me a while to sort this out, but after a few synapse cycles it finally makes sense. Thanks!

Avatar

I'm having the same problem.

I know that the helper method I have for current_user is not available in models. Since this goes

I read a post where someone suggested storing the current user inside the Model (http://rails-bestpractices.com/posts/47-fetch-current-user-in-models) but I'm leary of that solution because it seems like a bad idea to store something that might leak to other users.

This is a bit of a blocker since it's important to tie a particular tag to a user.

Avatar

All the necessary scripts (jquery, jcrop, avatar.js) are loaded but I'm getting a:
Uncaught TypeError: Object [object Object] has no method 'Jcrop'

I also have bootstrap.js loaded. I cannot figure out what's going on. Does anyone have any idea? Posted my question here, too:
http://stackoverflow.com/questions/14132170/uncaught-typeerror-object-object-object-has-no-method-jcrop

thanks!

Avatar

Try to wrap your pricing resource in a namespace in your config/routes.rb like this

namespace :products do

... your pricing resource ..

end

here's the railsdoc
http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing