Best ruby-on-rails questions in June 2011

Complex time-series statistical aggregation involving polymorphic associations

11 votes

Ok. Bear with me, as I need to provide a lot of contextual detail before I can solicit a reasonable answer to my question.

I have a site that allows you to make daily stock picks. The way it works is that you're prompted to make picks between companies that are facing-off for the day. For example, GE vs. IBM. You can make two types of picks: Performance (which stock will perform better?) and Total Volume (will the combined stocks trade at volumes higher or lower than X?). You're given 100 virtual dollars each day to make picks.

Ultimately, our goal here is to track which user makes the most money per pick in various categories (explained below) over the following periods of time: 5 days, 15 days, 30 days, 90 days, 180 days, 1 year, all-time. It's very simple to calculate how much money is made per pick. It's the total money made (or lost) / number of picks.

Now, each company that the user makes a pick on falls under a categorical hierarchy. Generically, the categorical hierarchy looks like this:

Division --> Major Group --> Industry Group --> Classification --> Company

Here are some examples:

  • Mining --> Metal Mining --> Iron Ores --> Brown Ore Mining --> Company A
  • Mining --> Metal Mining --> Iron Ores --> Brown Ore Mining --> Company B
  • Mining --> Metal Mining --> Iron Ores --> Limonite Mining --> Company C
  • Mining --> Metal Mining --> Iron Ores --> Limonite Mining --> Company D
  • Manufacturing --> Tobacco Products --> Cigars --> Stogies --> Company E
  • Manufacturing --> Tobacco Products --> Cigars --> Stogies --> Company F
  • Manufacturing --> Tobacco Products --> Cigars --> Cigarillos --> Company G
  • Manufacturing --> Tobacco Products --> Cigars --> Cigarillos --> Company H
  • …and so on…

There's a model for each category (and corresponding table, of course), and they are associated (think foreign_key) just like you see above.

There is a model for Matchup, with each record representing which companies are facing-off for the day. Each record keeps track of the starting and final stock prices for each company, as well as the the total trade volume.

Each Matchup has one or more :pick_prices that can change throughout the day. Normally, each matchup has a Performance Pick Price and a Total Volume Pick Price. The price determines what the pick will cost you and how much you earn for a correct pick. (Now, this is all just background info. You don't need to worry about those particular price calculations.)

At the end of the trading day, the user's picks are resolved. Picks are represented in a Pick model, with the following attributes:

  • user_id
  • amount_spent (e.g., $10)
  • result (e.g., WON, LOST)
  • pick (e.g., company A)
  • matchup_id
  • pick_price_id
  • amount_won
  • resolved (true or false)
  • created_at
  • updated_at

Currently, when each pick is resolved, another table is updated called pick_records, which has the following attributes:

  • user_id
  • recordable_id
  • recordable_type (Division or Major Group or Industry Group or Classification or Company)
  • picks (total picks made, regardless of pick type)
  • won (total picks won, regardless of pick type)
  • lost (total picks lost, regardless of pick type)
  • money (total money won)
  • money_per_pick (money / picks)
  • performance_picks
  • performance_won
  • performance_lost
  • performance_money
  • performance_money_per_pick
  • volume_picks
  • volume_won
  • volume_lost
  • volume_money
  • volume_money_per_pick
  • created_at
  • updated_at

As you can tell, this is a polymorphic model. The table aggregates the all-time pick record statistics.

So now here's the challenge:

Given the existing design, what do I have to do so that I can capture the user's pick records over the following periods of time: 5 days, 15 days, 30 days, 90 days, 180 days, 1 year, all-time? It needs to be simple, efficient, and fast!

I'm currently running Rails 2.3.11 on MySQL DB.

I don't see the need for table pick_records.
You can do a query like this for any number of days:

SELECT 
   user_id
   ,sum(amount_spent) 
   ,sum(IF(result = 'WON',1,0)) as WON_count
   ,sum(IF(result = 'LOST',1,0)) as LOST_count
   ,pick 
   /*matchup_id*/
   ,sum(pc.price) as price
   ,sum(IF(result = 'WON'),amount_won,0)) as amount_won
   ,sum(IF(result = 'LOST'),amount_won,0)) as amount_lost
   ,sum(IF(result = 'WON'),amount_won,-amount_won)) as nett_amount
FROM picks
INNER JOIN pick_price pc ON (pc.id = user.pick_price_id)
WHERE created_at BETWEEN DATE_SUB(NOW(), INTERVAL 5 DAY) AND NOW()
  AND resolved = 'true'
GROUP BY user_id, pick

Representing time periods in the UI and database

9 votes

I've recently adopted a project with an Employee model that needs to contain the person's available hours as an attribute.

The existing form uses 168 checkboxes to represent each hour in the week, and stores the information as seven 24 bit binary strings in the database, each bit acting as a boolean true or false for its corresponding hour in that day.

I'd really like to transition to something a little more elegant and manageable, but I haven't been able to come up with any simple solutions that match the existing implementation's flexibility.

Storing time periods as start and end times can be just as tedious to input when there can be multiple per day, and would likely make querying for availability at a particular time more complicated.

Is there a best practice for dealing with this type of information, both in the user interface and the database structure?

I would model the data in the database this way.

Employee/Day/Hour Relationship

There's a many to many relationship between the employees and hours for each day of the week.

On the UI side, you could use checkboxes for the days and multiselect list boxes to set the hours for the given day.

Rails validation :if => Proc.new or lambda ?

7 votes

I have found that in all examples (include rails documentation) that I have seen for the :if option of validation methods uses Proc.new instead of lambda, for example

class Foo < ActiveRecord::Base
  validates_presence_of :name, :if => Proc.new{|f| .... } # why not lambda here?
end

is there any reason for this? As far as I know, lambda

  1. Is more strict with arguments.
  2. Also return statement in lambda block returns from the block, not from calling function.

Both seems to be desirable behavior for :if option mentioned above, is there anything I am missing?

Thanks!

Both seems to be desirable behavior for :if option mentioned above, is there anything I am missing?

I'm guessing that:

It's more desirable to allow Procs as they don't care about the number of arguments. So I could easily write any of the below:

validates_presence_of :name, :if => Proc.new{|f| f.display_name.blank? }    # I care about 'f' here as I need it to check something.

... and:

validates_presence_of :secret_sauce, :if => Proc.new{ MyApp::REQUIRE_SECRET_SAUCE }    # I don't care about any arguments being passed in.

This may seem like a minor thing, but I guess it adds to the flexibility.

Ruby: is it acceptable to put more than one class in a file?

7 votes

This might be a bit of an esoteric question, but I just want to know what best practices are on this issue.

Yes, it is generally acceptable because it doesn't violate any principles of the Ruby language itself but it ultimately depends on the practices of your target audience or framework. (For example, Rails likes your classes to be one-per-file.)

However, if you are grouping classes with related functionality into a single file then you should also consider making them part of the same module for a namespace.

How to prevent rails (3.1) from firing 2 selects for same record?

6 votes

I have a CRUD users controller. When I open the "user edit" page in the browser, my log shows this:

Started GET "/users/1/edit" for 127.0.0.1 at 2011-06-21 20:09:37 +0200
  Processing by UsersController#edit as HTML
  Parameters: {"id"=>"1"}
  User Load (0.2ms)  SELECT `users`.* FROM `users` WHERE
   `users`.`id` = ? LIMIT 1  [["id", 1]]
  User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE
   `users`.`id` = ? LIMIT 1  [["id", "1"]]

In the edit action, I simply call a private function user, which returns

@user ||= User.find(params[:id])

The view looks as follows:

<%= settings_title(@user.username) %>
<%= form_for @user, :html => { :multipart => true } do |f| %>
  <%= render "form", :user => @user
  <div class="action"><%= submit_tag t("users.edit.submit"), :class => "button" %></div>
<%= end %>

The route is defined as resources :users do ...

Any idea how to prevent the second db access would be greatly appreciated!

Update:

It seems like the second DB SELECT can be prevented by calling

@user ||= User.find(params[:id].to_i) # notice the .to_i

in the edit action. I now get:

User Load (0.1ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = ? LIMIT 1  [["id", 1]]
CACHE (0.0ms)      SELECT `users`.* FROM `users` WHERE `users`.`id` = ? LIMIT 1

but is this the proper way to do it? Do you see any other side-effects of this solution?

Your #to_i workaround notwithstanding, if current_user is an admin and can edit any user record, then it would seem this is the correct behavior. It's just a coincidence that in this case current_user == user_to_be_edited and you're getting two db hits for the same data. In all the other cases where the current_user is editing someone else's user data, you will have to hit the database twice by necessity.

However, if current_user only ever edits his/her own data, then in your controller instead of:

@user ||= User.find(params[:id])

you would use:

@user ||= current_user

...under the assumption that user authentication has already occurred prior to getting to the action. In this manner, you will only have the one hit on the database that happens in authentication.

As a final note, in the former case, where a current_user admin can edit any user, if you really want to get rid of that one coincidental edge case where the database gets hit twice, you can do this:

@user ||= current_user.id == params[:id].to_i ? current_user : User.find(params[:id])

In this manner, you'll avoid the extra db hit when a user is editing his/her own data.

Facebook how to check if user has liked page and show content?

5 votes

I am trying to create a Facebook iFrame app. The app should first show an image and if the user likes the page, he will get access to some content.

I use RoR, therefore I can't use the Facebook PhP SDK.

Here is my iFrame HTML when the user has not liked the page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<link rel="stylesheet" type="text/css" href="style.css" />
<style type="text/css">
body {
width:520px;
margin:0; padding:0; border:0;
font-family: verdana;
background:url(repeat.png) repeat;
margin-bottom:10px;
}
p, h1 {width:450px; margin-left:50px; color:#FFF;}
p {font-size:11px;}
</style>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1" />
</head>
<body>
<div id="container">
<img src="welcome.png" alt="Frontimg">
</div>

And, if the user has liked the page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<link rel="stylesheet" type="text/css" href="style.css" />
<style type="text/css">
body {
width:520px;
margin:0; padding:0; border:0;
font-family: verdana;
background:url(repeat.png) repeat;
margin-bottom:10px;
}
p, h1 {width:450px; margin-left:50px; color:#FFF;}
p {font-size:11px;}
</style>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1" />
</head>
<body>
<div id="container">
<img src="member.png" alt="Frontimg">
<p>You liked this page</p>

Hi So as promised here is my answer using only javascript :

The content of the BODY of the page :

<div id="fb-root"></div>
<script src="http://connect.facebook.net/en_US/all.js"></script>
<script>
  FB.init({
    appId  : 'YOUR APP ID',
    status : true, 
    cookie : true, 
    xfbml  : true  
  });
</script>

<div id="container_notlike">
YOU DONT LIKE
</div>

<div id="container_like">
YOU LIKE
</div>

The CSS :

body {
width:520px;
margin:0; padding:0; border:0;
font-family: verdana;
background:url(repeat.png) repeat;
margin-bottom:10px;
}
p, h1 {width:450px; margin-left:50px; color:#FFF;}
p {font-size:11px;}

#container_notlike, #container_like {
    display:none
}

And finally the javascript :

$(document).ready(function(){

    FB.login(function(response) {
      if (response.session) {

          var user_id = response.session.uid;
          var page_id = "40796308305"; //coca cola
          var fql_query = "SELECT uid FROM page_fan WHERE page_id = "+page_id+"and uid="+user_id;
          var the_query = FB.Data.query(fql_query);

          the_query.wait(function(rows) {

              if (rows.length == 1 && rows[0].uid == user_id) {
                  $("#container_like").show();

                  //here you could also do some ajax and get the content for a "liker" instead of simply showing a hidden div in the page.

              } else {
                  $("#container_notlike").show();
                  //and here you could get the content for a non liker in ajax...
              }
          });


      } else {
        // user is not logged in
      }
    });

});

So what what does it do ?

First it logins to FB (if you already have the USER ID, and you are sure your user is already logged in facebook, you can bypass the login stuff and replace response.session.uid with YOUR_USER_ID (from your rails app for example)

After that it makes a FQL query on the page_fan table, and the meaning is that if the user is a fan of the page, it returns the user id and otherwise it returns an empty array, after that and depending on the results its show a div or the other.

Also there is a working demo here : http://jsfiddle.net/dwarfy/X4bn6/

It's using the coca-cola page as an example, try it go and like/unlike the coca cola page and run it again ...

Finally some related docs :

FQL page_fan table

FBJS FB.Data.query

Don't hesitate if you have any question ..

Cheers

UPDATE

Relatively to the comment I posted here below here is some ruby code to decode the "signed_request" that facebook POST to your CANVAS URL when it fetches it for display inside facebook.

In your action controller :

decoded_request = Canvas.parse_signed_request(params[:signed_request])

And then its a matter of checking the decoded request and display one page or another .. (Not sure about this one, I'm not comfortable with ruby)

decoded_request['page']['liked']

And here is the related Canvas Class (from fbgraph ruby library) :

 class Canvas

    class << self
      def parse_signed_request(secret_id,request)
        encoded_sig, payload = request.split('.', 2)
        sig = ""
        urldecode64(encoded_sig).each_byte { |b|
          sig << "%02x" % b
        }
        data = JSON.parse(urldecode64(payload))
          if data['algorithm'].to_s.upcase != 'HMAC-SHA256'
          raise "Bad signature algorithm: %s" % data['algorithm']
        end
        expected_sig = OpenSSL::HMAC.hexdigest('sha256', secret_id, payload)
        if expected_sig != sig
          raise "Bad signature"
        end
        data
      end

      private

      def urldecode64(str)
        encoded_str = str.gsub('-','+').gsub('_','/')
        encoded_str += '=' while !(encoded_str.size % 4).zero?
        Base64.decode64(encoded_str)
      end
    end  

 end

Many-to-many association with multiple self-joins in ActiveRecord

5 votes

I am trying to implement multiple relations between records of the same model via self-joins (based on @Shtééf's answer). I have the following models

create_table :relations, force: true do |t|
  t.references :employee_a
  t.string     :rel_type
  t.references :employee_b
end

class Relation < ActiveRecord::Base
  belongs_to :employee_a, :class_name => 'Employee'
  belongs_to :employee_b, :class_name => 'Employee'
end

class Employee < ActiveRecord::Base
  has_many :relations, foreign_key: 'employee_a_id'
  has_many :reverse_relations, class_name: 'Relation', foreign_key: 'employee_b_id'

  has_many :subordinates, through: :relations, source: 'employee_b', conditions: {'relations.rel_type' => 'manager of'}
  has_many :managers, through: :reverse_relations, source: 'employee_a', conditions: {'relations.rel_type' => 'manager of'}
end

With this setup I can successfully access the lists of subordinates and managers for each record. However, I have difficulties to create relations in the following way

e = Employee.create
e.subordinates.create
e.subordinates #=> []
e.managers.create
e.managers #=> []

The problem is that it does not set type of relations, so I have to write

e = Employee.create
s = Employee.create
e.relations.create employee_b: s, rel_type: 'manager of'
e.subordinates #=> [#<Employee id:...>]

Am I doing something wrong?

You can use before_add and before_remove callback on the has_many association :

class Employee < ActiveRecord::Base
  has_many :relations, foreign_key: 'employee_a_id'
  has_many :reverse_relations, class_name: 'Relation', foreign_key: 'employee_b_id'

  has_many :subordinates, 
           through: :relations, 
           source: 'employee_b', 
           conditions: {'relations.rel_type' => 'manager of'}
           :before_add => Proc.new { |employe,subordinate| employe.relations.create(employe_b: subordinate, rel_type: 'manager of') },
           :before_remove => Proc.new { |employe,subordinate| employe.relations.where(employe_b: subordinate, rel_type: 'manager of').first.destroy }

  has_many :managers,  
           through: :reverse_relations, 
           source: 'employee_a', 
           conditions: {'relations.rel_type' => 'manager of'}
           :before_add => Proc.new { |employe,manager| employe.reverse_relations.create(employe_a: manager, rel_type: 'manager of') },
           :before_remove => Proc.new { |employe,manager| employe.reverse_relations.where(employe_b: subordinate, rel_type: 'manager of').first.destroy }

This should works and make you able to use employe.managers.create
You may want to use build instread of create in the callback
Also you can read this question about this solution

Performance differences between '.find' and '.where' methods

5 votes

I am using Ruby on Rails 3.0.7 and I would like to know, regarding performance matters, what are differences between the User.find(<id>) method and the User.where(:id => <id>) method.

Under the hood, find does more or less what you're describing with your where. You can find the details in this post. That being said, if you're looking to grab a single record by id, then you might want to use find_one. That's what find winds up doing when you call it with a single argument of an id, but you'll skip past all the other code it needs to run to figure out that's what you wanted.

I'm using Rails3 with tinymce. How to present user close browser javascript then input xss?

5 votes

I have a site written by Rails3. My post model has a text column naming "content". In the post panel, html form sets up "content" column to textarea field with tinymce. In front page, because of using tinymce, the post.html.erb code needs to implement with raw method like <%= raw @post.content %>.

Okay, now if I close browser javascript, this textarea can type without tinymce, and maybe user will input any xss like <script>alert('xss');</script>. My front will show that alert box.

I try to sanitize(@post.content) in posts_controller, but sanitize method will filter tinymce style with each other. For example, <span style='color:red;'>foo</span> will become <span>foo</span>.

My question is: How to filter xss input and reserve tinymce style at the same time?

The sanitizer can be set to allow the style attribute. In your config/application.rb add:

config.action_view.sanitized_allowed_attributes = ['style']

The sanitize method also has defaults for which css properties and keywords it allows. See sanitizer.rb allowed_css_properties and allowed_css_keywords to get a list of the defaults.

To add some that aren't currently allowed add this to your config/application.rb:

config.action_view.sanitized_allowed_css_keywords = ['puke']

--

If you're doing anything more complicated than this then you'll need to write some code. I don't recommend doing this from scratch, check out the Loofah Gem for a good library for writing html scrubbers.

In Rails 3.1, is it really impossible to avoid including duplicate copies of stylesheets?

5 votes

I'm running into an upsetting issue when trying to share variables and mixins across Sass stylesheets.

If I use @import to include a global stylesheet – one which includes global colors, mixins, etc. – it gets included again when Rails combines all stylesheets referenced in the manifest file.

Alternatively, if my manifest file does not include the global stylesheet, but multiple files in the manifest import it, the global stylesheet will still be included more than once. GAH.

How can you get around this? Does Sass have secret inclusion guards? Am I doing something terribly wrong?

I do not understand why this is an issue for your specific question. Variables and mixin declarations should not lead to any selectors or declaration blocks in your generated css file. However, when you use mixins for multiple selectors, the corresponding declarations are included for every such selector. This is how SASS handles it.

So as long as it's only variables and mixins, it should not matter if they are included multiple times in the manifest file since this does not have an effect on the compiled file. On a site-node, I believe it to be good style that SASS forces you to explicitly declare each file's dependencies.

If, however, you also have selectors and declarations in the base file that you want to inherit from in separate files, then indeed these will be included multiple times even in the compiled file. It would still be interesting to know how to prevent this by configuration. However, if you treat each of your sass files to be one encapsulated set of rules without cross-file inheritance, then you should be able to prevent your issue by convention.

Differences between *, self.* and @* when referencing associations/attributes in Ruby/Rails Models/Controllers

5 votes

Assuming a Rails Model with persistent / non-persistent attributes, what is the best practice regarding referencing them? If you look at code publicly available, different patterns are used.

For instance, if you have an association from one model to another. What is the difference between using self.association_name and @association_name?. What is the preferable way?

Same as with non-persistent attributes defined with attr_accessor :attr in Models. You can reference them with both approaches, self.attr and @attr. What is the preferable way?

self.x/self.x=y are always method calls.

(self.x is just sugar for self.__send__(:x) and self.x = y is really just sugar for self.__send__(:x=, y))

@x, on the other hand, only refers to an instance variable.

Using @x will not work with AR associations as AR only defines x/x= (which are methods) for its magical operation. (AR essentially just "captures" intent access through these methods and routes through its own internal data structures which are unrelated to any similar-named instance variables.)

attr_accessor allows "accessing both ways" because and only because it uses the same-named instance variable as it's backing (it has to store the value somewhere). Consider that attr_accessor :x is equivalent to:

def x; @x; end
def x= (y); @x = y; end

Happy coding.