Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Hammertime
May 21, 2003
stop
I'm using RoR to commercialize web app version of a traditional rich client app.

I've been learning as I go. It's been all roses except for a few times where convention/language immaturity has hosed me. I'd sure love some more thorough documentation, that's for sure.



One obscure but confusing pitfall:
Rake is just a ruby gem. Due to this, it also seems to suffer from documented problems if you use various "reserved words" (not mentioned anywhere, just stuff that crosses over with a few rake methods). I didn't think this would be the case due to the separate namespaces but it seems I'm wrong.

I was creating some randomly generated sample data in a rake migration file for performance testing, and I spent an hour trying to work out what I was loving up. Turns out having validates_presence_of :task creates a conflict, due to the use of task in Rake.

I don't fully understand how this conflict occurs, but apparently there are a handful of other words/symbols that can't be used when raking.

Adbot
ADBOT LOVES YOU

Hammertime
May 21, 2003
stop

SeventySeven posted:

Disclaimer: Very new to RoR.

I've been building a small project recently and have been using migrations to build my database since apparently it's the best way to do it (?) and I'm trying to get used to The Rails Way. I realized that a migration I just created to change a field was pretty stupid so I wanted to roll back to the version beforehand. Of course, being the idiot that I am I just had to write this code...

...
So no rolling back for me. :downs: My question is, how do I do this manually and cleanly? I tried commenting out that exception and running rake db:migrate VERSION=3 (the above file is 004_...) but nothing appears to have happened. Should I delete the entire migration file, manually editing the version number in the scheme_info table and then running rake db:schema:dump? Or will this have undesired consequences? Thanks.

In the process of scoping out the model/database design for my latest project, I've hosed up my migration files a bunch of times through having them abort half way (and leave a table), thanks to mispelling table names etc.

Load up mysql, drop the database, create it, run "rake db:migrate" on the now empty database.

There are a variety of ways to get around your situation, but I don't think it's worth the effort. I just fix it up, then go from scratch.

For me, sometimes rake just starts flaking out for both increasing and decreasing the database version. It runs, doesn't do anything, and doesn't create any output. Again, I just clear out the database and go from scratch. Reality is, rake is an awesome but buggy/immature tool.

Edit:

Oh, and assuming this is a pre-production system. Don't bother creating separate migration files for an alter column. It's easier to migrate back to version 0, change the table declaration to include the column, and rake it back to the latest version. Before you actually push the system live, the practice is to group all the migration files together into a single file (not including sample/starting data if you have any). Ideally there's a migration file for each version of the system that gets pushed into production, having separate migration files for development is just a temporary measure.

Hammertime fucked around with this message at 09:51 on Sep 24, 2007

Hammertime
May 21, 2003
stop

Grob posted:

This can actually be dangerous unless you are the only person working on the project. If multiple people are checking out your source, going back and editing earlier revisions is sure to ruin their day :) Just a warning for the new guys.

Very wise words.

My prototype was a 1-man show. It's only now scaling up to a small project team(3ish devs). I do believe it's worth consolidating the migrations assuming you communicate it with other team members and make sure everyone has their work checked in.

You remind me of how I dislike working with version control in RoR :(

I find the generators in ruby just make it more awkward to add all the new files to subversion. If only there was some magical versioning solution.

Hammertime
May 21, 2003
stop

vg8000 posted:

:confused:
code:
./script/generate scaffold_resource Whatever name:string --svn
This will add your generated files into SVN automatically.

...

...

I had no idea, thankyou.

Hammertime
May 21, 2003
stop

vg8000 posted:

Mysql's port is 3306, Apache's is 80 (unless you changed the ports they listen on). You might have another web server running on port 80 or something, check that first.

i.e. make sure IIS isn't stealing 80.

Hammertime
May 21, 2003
stop

SeventySeven posted:

I've got a controller set up like this:

Basically, I'm trying to determine the entry point for method2 (which can also come from the browser). Obviously I know about the request object, but is there any way I can tell if method2 was entered from a redirect?

I'm sure there are ways of doing exactly what you want, but if possible you're better off not relying on a referrer.

Some alternatives:
- If you're just doing processing in method1, why not just render method2's template afterwards. Alternatively, break up the processing into a private non-rendering method and call it from method2.
- Write to the user's session collection at the end of method1, check/erase it in method2. This method is still flawed though, as if the user doesn't reach method2 after the redirect they'll have a session token sitting around unused.
- Though probably not what you're after, flashes can persist after a redirect.

Hammertime
May 21, 2003
stop

SeventySeven posted:

Can anyone tell me why this WON'T loving INCREMENT?


collected is an int field in the order_item table defaulting to 0 (though I've manually set it to other values with no success). @item is a valid object.

Based on the API source, I believe it's expecting the name(or maybe the symbol) of the attribute.

Try: @item.increment!('collected')

Hammertime
May 21, 2003
stop

asveepay posted:

I had completed a lot of work on an application and then 2.0 released just as I realized I had to rewrite a significant chunk of my app.

If you have a moment could you expand on what is the cause of the rewrite.

I've got a project sitting at 1.2.6, but was hoping to seamlessly upgrade to 2.0, I didn't realise there were any changes that would cause a re-write of a section.

Hammertime
May 21, 2003
stop

Xgkkp posted:

Anyhow, I have run into a small problem: I'm making a site, with lots of static pages and then a couple of ruby pages for management and registration. How do I integrate the two? I don't want to have to make separate views for every single page (or dynamically generate them on every view with link_to's), but I can't just put in static pages and link to them normally, because then if I do relative links depending on which controller/method I am in they wil be invalid.

Can you just put it in the /public/ directory, I haven't found what I'm looking for yet, but there's probably a way of getting the application root directory (as a foundation for making your links) out of a config variable(that you may have to set manually).

Hammertime
May 21, 2003
stop

savetheclocktower posted:

RJS isn't a leakproof abstraction. It's really just a way to place Ajax logic in your controller, where it makes sense to live. If you try to write everything in pure RJS, never touching JavaScript at all, you'll just end up uglifying your controllers.

And slowing your application. The escape method used in updating page content through rjs (as opposed to doing a prototype Ajax Update) is pretty slow.

Hammertime
May 21, 2003
stop

SeventySeven posted:

How do I check my app's compatability with Rails 2? I was under the impression that 1.2.6 would show deprecation warnings, however, uhh... where does it show them? I can't find anything in the development.log or in the command line server output.

That's a good thing sir.

It puts them to the development console/log.

Depreciation stuff includes, using Array.concat calls without brackets, and various other minor things. It's designed to be forwards compatible, so not everyone's going to get depreciation warnings. I've got a fairly large/complex system and I'm only getting 1 or 2 total.

Hammertime
May 21, 2003
stop

SeventySeven posted:

I set ENV['RAILS_ENV'] ||= 'production' in environment.rb. It says do that if you can't do it the better way, but in typical Rails fashion it doesn't tell you what the better way is? :confused:

A small note, I believe the usual way (at least the one I use is morelike):

ruby script/server -e production

The same argument can be used with mongrel_start

Hammertime
May 21, 2003
stop

Zaxxon posted:

I kinda thought the whole point of RoR is that you didn't have to gently caress with all the html and SQL stuff and could do it through ruby.

You're right about the point, that's a major part of it. The automation though is also based on having a strong familiarity with more manual/raw web development with php/python etc.

While rails removes a lot of the boiler plate code in web development, I believe you need to have the low level knowledge to use rails without shooting yourself in the foot. I might be wrong, but RoR has a sizable learning curve even after having a strong foundation in web programming (I've been a commercial web dev for 5 years, rails dev for 6ish months).

Hammertime
May 21, 2003
stop

Nolgthorn posted:

That's not true, I learned some about Microsoft SVN while I was getting my MCAD in school, but MCADs don't help in Rails!

Should I know about SVN, Mongrel, page caching and stuff because I don't know about those things. I've always deployed by hand to whatever was available on the server, I've created about 20 commercial web sites in the last year.

You should know about SVN, but you can learn this in 10 minutes. It's source control and it's drat easy/simple.

You should know what Mongrel is. A pure ruby web server perfect for development that can also be used in production if you spawn a handful of them and proxy to them.

You should read some basic caching tutorials, page/fragment etc.

Without really knowing the scope of your knowledge it's hard to recommend further topics, but most of the stuff is covered in blogs.

Edit:
- Read a good tutorial on eager loading

Hammertime fucked around with this message at 00:18 on Feb 5, 2008

Hammertime
May 21, 2003
stop

atastypie posted:

You can run multiple versions of rails on the same server without problems. If using the gem, check your environment.rb to see what gem version is required. You can install a specific version of a gem using the -v flag, I believe. You can also rake freeze your version of rails and then you don't need the gem to be installed. Freezing a gem will place it in /vendor of the rails project, and not require the actual gem to be installed on the server.

I thought instantrails was depricated? You're always going to be better off installing ruby + rubygems => gem install rails, and I suggest you try that instead of using Instantrails.

The MySQL errors: do you have the latest mysql gem installed?

I haven't used Hobo. I'd try their mailing list, though.

Just to complicate things ...

In my opinion you're better off just using the latest version of the InstantRails package. Having an additional stack of apache/php/phpmyadmin can be really helpful for mysql administration (if you cant be bothered to install the desktop clients).

InstantRails is far from deprecated. It was temporarily deprecated for a few weeks, but was revived and now comes bundled with Rails 2.0.2 and the latest versions of everything else.

I'm happily using InstantRails at work and home for my commercial development until the new revision of the macbook pro comes out.

Doing things manually from rubygems also isn't a bad idea though, but there's nothing wrong with InstantRails.

Hammertime
May 21, 2003
stop
I can chip in on deployment advice for medium-larger apps (no single point of failure etc.).

Main stuff I've deployed:
1. Software as a service web app that just launched ( nginx load balancers/asset servers -> apache + fcgid -> memcached + replicated mysql). Only architecture that could work for us, long story.
2. Highly dynamic(uncacheable) public site (nginx -> mongrel cluster -> memcached + oracle)

I love nginx & memcached.

I've only deployed on dedicated/larger virtual servers, so I can't really advise for smaller slice based arrangements.

Hammertime
May 21, 2003
stop

drjrock_obgyn posted:

Bump because Rails 2.2 rc1 is out:

Improvements include:
* Thread safety
* ActiveRecord connection pool

Is this moving in the direction of parallel database access?

Hammertime
May 21, 2003
stop

WHORENDOUS posted:

is there a good reason why ruby doesn't support the ++ or -- operators or is it literally just to piss me off?

I have no idea of an official answer, but after a year and a half, I've decided without any justification that it's for consistencies sake.

a += 1
a += 2

vs.

a++
a += 2

Edit: Pretty much just to piss you off.

Hammertime
May 21, 2003
stop

Sharrow posted:

How is Passenger? I've got a couple of nginx+mongrel apps that are about to be moved to a new system and get some more development time, so if it's as good as it sounds then switching could be pretty easy.

I've run it in light production for a while without issues. I never seemed to get the memory gains that ruby enterprise edition promises, but everything was nice and snappy. I still sit nginx out front of apache.

Hammertime
May 21, 2003
stop

Panic! at the Fist Jab posted:

Based on my experience, this is essentially accurate. It also takes about 30 seconds to hit a site after something like 2 minutes of no one accessing it. Phusion Passenger is absurdly slow and no amount of tinkering with the configuration seems to be able to ameliorate it.

There's something seriously wrong with your phusion deployment.

I've had to benchmark phusion for a multi-app site (40 apps were used to test). Spool up time from scratch was always in the range of 2-5 seconds.

Hammertime
May 21, 2003
stop

Flobbster posted:

I finally took the plunge and started teaching myself Rails a few days ago -- my dad wanted me to design him a simple website, and since I'm equally inexperienced in just about all webapp frameworks (except for Apple WebObjects, which I know better than I ever wanted to know :gonk: ), I decided RoR was the one I wanted to pick up. I'm loving it so far, and I've been trying to immerse myself in "best practices" out of the box, and I'm now in a situation that's probably simple but I'm not sure exactly what's best to do here.

...


That's a pretty cool/crazy undertaking (in a good way).

You've got a couple of choices I can think of:
- YAML file that gets loaded in environment.rb and exists as a hash in the global name space
- Database rows? Not as good as the yaml file really.
- Lib files? Reasonable but loaded yaml is more elegant.

Small note: make sure to turn on page caching for the stylesheets to ensure you get the best of both worlds, flexibility without the performance hit.

The yaml loading can be achieved through something similar in your environment.rb file:

code:
require 'yaml'
CSS_CONFIG = YAML::load(File.open("#{RAILS_ROOT}/config/css_config.yml"))
References can then be pulled through

code:
background-color: <%=CSS_CONFIG["secondary_main_color"]%>
You could also "helperize" the calls to abstract it by a degree (and clean things up a little) by declaring an application helper method for get_css_property.

code:
def get_css_property_thing propery_name
  CSS_CONFIG[property_name]
end
I don't think what I'm suggesting is ideal, but that's all I can think of for the moment ;)

Hammertime
May 21, 2003
stop

atastypie posted:

Weird, I swear that when I started out with 1.6 that you had to restart your server to get the routes file to reload. That, plus comments like '# Be sure to restart your web server when you modify this file.' in environment.rb made me just assume anything in /config required a restart. I've also done a lot of work with Radiant, and any routes found in an extension require a restart in order to be found. Combine those two and I guess I learned a bad (useless?) habit.

I believe the restarting for routes requirement was only removed in 2.0+, though I could be wrong on this.

You also have to restart if you make any modification to files in lib.

I've got a bad habit, I restart my development mongrel waaaay too much.

Hammertime
May 21, 2003
stop

skidooer posted:

No you don't, unless you explicitly require the file that is. But apparently 2.2 really does have a problem with routing to new controllers without a restart. I just encountered it.

Well, yes, but what's the point in having lib files if you don't require any of them?

Hammertime
May 21, 2003
stop

Nolgthorn posted:

I have an Entries model and I have a Votes model. Each Entry has many Votes and each time that an Entry is loaded, the associated Votes will also need to be loaded, is there a way I can use scope to automatically :include => :votes on each request?

Or is this not good practice?

Honestly, it's not good practice.

Evil Trout's suggestion is better though. I think it's pretty important to be able to see the eager loaded tables (or at least scopes that suggest something funny's going on) at first glance for every ActiveRecord find call.

code:
class Entry
  has_many :votes
  named_scope :with_votes, :include => :votes
code:
Entry.with_votes.all :order => "created_at DESC", :limit => 10

Hammertime
May 21, 2003
stop

Nolgthorn posted:

Why are the partials being loaded slowly, in production are these partials just going to be in memory or something?

Thanks in advance for both questions

Partials are just never going to be really fast. They do have very different performance characteristics in development mode though, since I believe they're manually loaded from disk and parsed every time. Try turning template loading caching on manually in your environments/development.rb to get a better idea. In production these partials should sit loaded in memory.

code:
config.action_view.cache_template_loading = true
I think the times you're seeing are largely the parse times for templates as opposed to their rendering.

You're hitting against one of the most frustrating parts of working with rails. The trade off between performance and clean code structure.

Hammertime
May 21, 2003
stop

Nolgthorn posted:

I may need to call the column something different if I want to have more control over it I guess.

Honestly, you're fighting against the tide of convention. I'd just call it something else (last_updated_at/on etc), add before filters to change the attribute automatically if you want to retain some of the behavior.

Minor code tips based on your sample:

It might be worth altering the the thread before the save call to minimize on the number of database writes, so only one save is called.

code:
if @first_post.valid? and @forum_thread.valid?
  @forum_thread.generate_preview(@first_post) # sets the internal preview variable, doesn't save
  @first_post.save!  
  @forum_thread.save!
The line "@first_post.save" is a bit funny/a code smell. It's not bad in this instance since you're checking validity immediately before, but I've found it's a good habit to never allow an unchecked .save and risk the possibility of silent failure (and the fun debugging times that ensue). If it's on a line by itself, and should pass anyway, I just use the .save! method, to ensure it's easy to track down if I've introduced a regression bug etc.

One more minor thing to think about is transactions. If you're saving more than one thing at a time, it's probably worth batching it in a transaction. This is a really unlikely circumstances, but what if the DB server died after the "@forum_thread.save" call, but before the "@first_post.save" call, you'd have invalid/inconsistent data. Not a big deal for threads/forums, but something to consider for other projects.

Hammertime
May 21, 2003
stop

NotShadowStar posted:

So next up on the list is I'm writing a model for handling experiment data. Experiments are always done on plates. Plates, in my context, are generally a 2d array that holds stuff. In a separate project I wrote a basic Plate class that's pretty much a 2d array with pretty accessors with other helper stuff, and specialized Plates for their own experiment are subclasses and add their own stuff.

...



Firstly, 1 row per experiment is probably the right way to go (provided you don't need to pull experiments based on their results). One row per element is an extremely wasteful approach.

Secondly, if you've got various different experiment types with differing data requirements your have a couple of choices. The first is to have one table per experiment type. The second is to use RoR's single table inheritence and base multiple models around it, I'm not overly familiar with this approach, but it should be fine given you only have 15,000ish experiments.

Splitting the experiment data off into it's own table and giving it a polymorphic association back to the experiment tables is also an option.

As to how you store the data itself, I'd need a bit more information on what each element details, but storing it into a text column with a small bit of encoding is my current gut feeling.

MySQL really isn't friendly to multidimensional data.

NotShadowStar posted:

The other thing is since there will be several models that are similar but have different properties for different types of experiments or similar data I feel like I should be looking into writing an acts_as, but I don't know the first thing about that.

As an intermediary to plugin writing (as this can be a slightly tricky endeavor on your first go), perhaps just use a mixin for common functionality and include it in each of your experiment models.

Hammertime fucked around with this message at 03:54 on Jan 3, 2009

Hammertime
May 21, 2003
stop

GroceryBagHead posted:

And if you used Passenger it would be even faster.

Pretty much ... Nginx + Passenger = Greatest rails webserver combo ever.

Hammertime
May 21, 2003
stop

bitprophet posted:

The main thing to grasp here, and this goes for any ORM, not just Rails', is that there's your in-memory object and your database row, and they're actually completely distinct from one another until something happens to either read from, or write to, the database.

Any ORM except for (N)Hibernate (out of the box) that is. Even when you don't explicitly save, crazy persistence magic still happens! </tangent>

Hammertime
May 21, 2003
stop

Operation Atlas posted:

If you're using an old version of RMagick, there's a memory leak in it. Once the mongrel process gets too big the OS will kill it. That's my #1 guess as to what's going on.

First, upgrade to the latest RMagick/ImageMagick combo. Second (if possible) upgrade to Nginx/Passenger. Way better than mongrel.

Another vote for Nginx+Passenger. Having to care about mongrels was horrible, let alone having to combine RMagick (i.e. memory leak central) with persistent mongrels. Talk about an admin nightmare.

If you're just doing basic stuff, try MiniMagick, it's a very thin wrapper around calling ImageMagick with shell commands with the benefit that your Rails processes won't leak memory/bloat. It's not exactly speedy, but it's clean.

Hammertime
May 21, 2003
stop

NotShadowStar posted:

I made it a habit since Rails < 1.0 to always kill the development server when I'm not interacting with the app. It's much better than it used to be, but it's still sometimes questionable when you need a server restart or not.

Anything in /app gets reloaded cleanly, anything in /lib /config or gem related needs a restart. I restart on route changes too, though not sure if that's required these days.

Hammertime
May 21, 2003
stop

Evil Trout posted:

Actually /lib hasn't needed a restart in at least a year's worth of Rails releases.

Interesting, thanks! Fair enough, I hook some /lib stuff through my initializers, so I have to anyway. I've been on a single rails project for over a year, so my misconception makes sense.

Hammertime
May 21, 2003
stop

NotShadowStar posted:

I went down that route and decided that they all suck rear end. Most of them depend on RMagick which is loving terrible.

What I ended up doing is generating json data (easy with standard records doing to_json) and using flot to display it and give the user more control over the graph. Only problem is since IE is loving terrible and doesn't support canvas flot uses a VRML JS wrapper, and IE's JS performance is such poo poo it can take unreasonably long. About 8-10 seconds on a modern system with 384 points of data, whereas Firefox >3.5 and any Webkit is instant.

I've had to do some rails graphing again and I've had the same experience, gently caress Scruffy/Gruff etc. We've started using flot (and failing that I probably would have gone back to google charts again), but again we don't need to support IE for this app since it's internal.

Hammertime
May 21, 2003
stop

Ghotli posted:

Just chiming in. We use flot as well. I've come to the conclusion that if they're looking at my charts in IE6 then gently caress them. They're getting what they deserved.

Amen, http://emotify.com/acy149/

Hammertime
May 21, 2003
stop

NotShadowStar posted:

My advice is avoid RJS. I think they went a little to far saying 'ruby for EVERYTHING'. RJS is really confusing and really really badly documented (probably goes along with Prototype is badly documented), wheras putting JS in the view template (or better, a partial that contains the script) is much easier.

Rails 3 is much nicer since it doesn't dump Javascript all over the page but instead creates specific named HTML ids and classes that you can use any JS framework you want to target those classes.

Echoing this. I never really saw the point to writing Javascript hooks in ruby, when it takes around the same amount of code as it does in Javascript. It's just adding an awkward layer of abstraction. Plus out of the box it doesn't support jQuery, which I'd heartily recommend over Prototype.

Hammertime
May 21, 2003
stop

8ender posted:

I have an old copy of Agile Development with Rails 2nd Edition. It seems to cover Rails 1.9. Would starting with this book put me in a bad place given that Rails 2 is mature and Rails 3 is imminent? Should I look around online for some Rails 2 tutorials?

Hard choice, from the RailsConf talk by DHH (http://www.youtube.com/watch?v=b0iKYRKtAsA), several of 37signal's products are already running on Rails 3 in production, so it must be pretty drat close to imminent. On the other hand, there's little good tutorials/doc online and I found that the Agile Dev with Rails books were awesome introductions to Ruby on Rails back when I was learning Rails for the first time.

I'd probably use the Agile Dev with Rails book that you have and keep an eye on the new way of doing Routes and AREL with Rails 3, so you know which parts are going to be replaced.

Hammertime
May 21, 2003
stop

8ender posted:

Coming from a Java background Ruby and Rails is making my brain fry like an egg. Everything is balderdash and seems to operate using very sexy black magic.

Learning Ruby plus Rails is a headfuck that won't end anytime soon. It's magic/voodoo all the way down, where ruby starts and rails ends is a big blurry mess. It took me a couple of months of cutting RoR (and delving into the source when curious) to really understand how it all works.

Hammertime
May 21, 2003
stop

Gordon Cole posted:

What would be the best way to have a one-off piece of data in the database? Things like a little blurb at the top of the main page or the content of an "about" page -- I'd like to be able to edit that kind of stuff from the page itself, so I don't want to hard code it into my views. But it also seems kind of silly and messy to create an entire model and controller for little stuff like that.

Is there a recommended method for doing stuff like this?

Honestly ...

I'd just create a simple model (pk id, string name and a blob/text for the content, plus an int version column could be useful) + controller. Using a rails model generator really doesn't take long "ruby script/generate model page_content name:string content:text version:int", and poke through "map.resources :page_content" in routes.rb.

Wrap the displaying of the content in a 'cache' block so it hits memcache instead of the database for drawing the fragment and you're almost there.

Hammertime
May 21, 2003
stop

NotShadowStar posted:

What's wrong with normal SQL ordering? Rails 3 query interface makes it really easy.

http://edgeguides.rubyonrails.org/active_record_querying.html#ordering

Pretty much. While in theory joining and sorting isn't always guaranteed when sorting a joined table, it works fine for the post->section structure you describe.

I assume you're sorting by section name when you talk about sorting by section.

Old school AR:
code:
# by post title
Post.all(:include => :section, :order => "posts.title ASC")

# by section
Post.all(:include => :section, :order => "sections.name ASC")
The only case that ActiveRecord never covered sufficiently was joining tables and applying a named scope to the outer join. You could kinda fix this by creating an extra association to cover it, but then that association couldn't take arguments. This has since been solved in AREL though.

Otherwise, ActiveRecord has you covered, and it definitely has you covered for the situation you describe.

Adbot
ADBOT LOVES YOU

Hammertime
May 21, 2003
stop

NotShadowStar posted:

Alternately buy the best book there is

(Really wish pragmatic programmers had affiliate linking)

Quoting this because this book is simply the best way to do it. I used it, all my rails devs used it. It's efficient and fun.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply