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
zigb
Mar 21, 2007
I'm a PHP coder who is nearing completion on my first RoR project. The project is to port someone's large spaghetti bowl of a MsAccess app to MySQL/RoR. I (alas!) can't change the database layout, including table and column names, due to design constraints beyond my control. Here's what I liked and disliked about the RoR experience.

The Good:
- Database migrations. These are truly lovely. At any time I can drop the entire db structure, then recreate it and copy the live data over from SQL Server. Or just downgrade the data migration and then run it again. This allows me to test against a copy of the live data and then reset my copy once I feel I've corrupted the data too much.

- Enforced (or at least strongly encouraged) MVC design pattern. Sure, it's nice.. that said I was using MVC previously in both CakePHP and later my own simple custom framework.

- Helpers are cool. I'd rather type <%= text_field :object, :accessor, :etc %> than <input type="text" ... />, and they become especially cool when I need to read the input data in a controller. form_for is bitchen.

The Bad:
- Documentation. For gently caress's sake people, at least pretend like you're trying. I'd say around 90% of the helpers and controller methods I found on api.rubyonrails.org had "options = {}" in the signature without any further information. In the entire page. For as many people here hate PHP, some of you must have tried it. Remember the documentation? It has a search box, for one. It also tells you exactly which PHP versions the function in question works in, and any differences between those versions. The PHP docs are also available in something like 22 different languages.

- Server restarts. Our dev server is also, unfortunately, a production server for different apps in other languages. (don't blame me, I didn't do it :(). Under Apache/FastCGI/RoR there are too many times we need to restart Apache. Changed something in environment.rb? Restart Apache. Added/Edited something in the /lib path? Restart Apache. This makes any sort of iterative development of libs/mixins a huge pain in the rear end. Particularly since I have to go beg the sysadmin to restart Apache.. How is this even considered acceptable? Is it just assumed that one server will run only one RoR app? There are live apps being taken offline every time I need to update a library.

- SQL Logging. Didn't work, even when I triple checked that the /tmp and /log dirs had proper permissions and that logging wasn't disabled in the environment files. I even tried chmodding /tmp and /log to 777, still no logs. There were a couple situations where knowing what sort of SQL ActiveRecord was generating would've saved us some serious headaches.

The Gotchas:
- 'type' db field. The original MSSQL db had a 'type' field in one of the tables. It can be used as a regular field, but only after putting a dummy value in the model for inheritance_column, then accessing the member as object[:type] instead of object.type. This of course breaks all attributes= and object.attributes calls, requiring an extra line after them that explicitly sets object[:type].

- You still write SQL, for any sort of advanced find / sort. Not that I mind writing SQL, but I prefer to write it in one large understandable chunk instead of splitting it up into mini-clauses, like :conditions => "[some sql]", :order => "[some sql]", etc. Most find queries that required a JOIN or two had to be written using find_by_sql. Again, I like sql, but I feel like I'm cheating every time I use it in Rails.

- Controller initialize function. It causes "Internal Server Error" when I put simple logic in there. Example (this kills rails): "if null != params[:a_param]; end". Same thing when I put the logic in question into a method and call it from initialize. No problems when I call that same method from one of the actions instead.

- Different expectations for overriding ActionController::initialize and ActiveRecord::initialize. Many working code examples override initialize in a controller without calling super(). To be sure this was safe, I even looked at the code for ActionController::initialize which is an empty function. Later, assuming that this was a Rails convention (remember "convention over configuration"?), I overrode a model's initialize method without calling super. Hilarity ensued as I tried to track down why an object created in one line had none of its members in the next, even though it wasn't nil.

In conclusion
Rails didn't work for me this time around. Once I've finished this project I'll gladly put Rails down for a time and maybe try again once it's matured some. Perhaps it's just that the project required too much custom tweaking, I'm not sure. I came up against ActiveRecord's limitations several times, along with some of the more esoteric Rails gotchas. I've only listed a few here, but I'd estimate that 15 - 20 minutes of every hour were spent looking for help when Rails' "magic" turned evil, or looking for documentation on helpers. In most cases I'd find the answer on somebody's blog, usually 3 pages into a google result set, after trying in vain to find the relevant info in RoR's documentation.

While the above issues were all annoyances, the need to restart Apache after making code, not configuration, changes is the kicker. In contrast, we have a PHP application that's been running for three years solid without any downtime except for electrical problems/server room maintenance. We make changes to the codebase fairly regularly without ever requiring an Apache restart.

For my work I'm going to continue using PHP, most likely with the Zend Framework. I'm also going to check out Zope/Plone which is supposed to combine a built-in CMS with some new novel way of doing ORM. I feel Rails still has a way to go before it can offer more to your average developer than "Create a blog in x minutes".

Adbot
ADBOT LOVES YOU

zigb
Mar 21, 2007
First off, I want to say that I really appreciate people taking the time to try to address some of the issues I had mentioned with our rails setup. When I hit the post button late last night I was expecting to be flamed out of hand. Maybe I'll have to spend more time in the COBOL cavern and try to help out where possible.

I'll address skidooer's responses because he was very thorough and his responses captured the gist what everybody seems to be saying:

skidooer posted:

Is there any reason why you aren't developing on your local system? That is the Rails way.


I would have preferred that. I work on a machine that is managed by our IT staff, who are extremely paranoid and won't install anything resembling a server, even if I can lock it down to local access only. To put things in perspective, I had to get permission from my supervisor and dept. head before they would install WinMerge. Basically, local dev is out.

anal wink posted:

Is there a reason you're not using mongrel?

wunderbread384 posted:

...why are you running FastCGI for your development server?

It's not my server, I have no choice. In fact, I barely have a user account. I'm grateful for the comments people left re: FastCGI because if I can eliminate the Apache restarts (well, make the case to the server admin and hopefully get a change) I'd be a much happier camper.

In order to help resolve my ignorance on the matter, can I run Mongrel behind Apache? The decision has been made that Apache WILL be our http server, so any solutions I come up with need to be Apache-centric.

skidooer posted:

Unless you were using an ancient version of Rails, or running in production mode, that isn't true.


Rails 1.2.3 on Ruby 1.8.5. We're currently supporting another RoR app written by a different dev on this same box, so neither of those are subject to change. Also, I'm running in development mode.

skidooer posted:

[re: SQL Logging]I've never seen it not work in development mode.

I hate always being the exception to the rule! :(

skidooer posted:

I'll assume it's your use of a schema that wasn't designed for ActiveRecord that you had to write a lot of SQL to work around those limitations.

skidooer posted:

find(:all, :joins => 'INNER JOIN bar ON bar.foo_id = foo.id')

Likely too true. I'll have to try that :joins thing, btw, I was totally unaware it existed ;)..

grob posted:

-- what kind of joins are you doing that aren't handled elegantly by ActiveRecord?


Don't say you didn't ask for it :) ... This is for a reports type section of the site. The nastiness of this has much to do with the enforced crappy DB schema. Here's as brief an explanation as I can muster.. Payments belong to Schools and Costs. Costs belong to DatabaseInformations, which are really what this app is tracking. I need a list of all payments within a date range, for a few specific Schools. The date range is determined by Cost.subscriptionStart and Cost.subscriptionEnd. I need to order these Payments for display by the Payment.school.schoolName, then Payment.school.library, then Payment.cost.databaseInformation.databaseName. Final note: this report gets run perhaps twice in a blue moon, so the inefficient SQL doesn't make me too nervous.

@skidooer - I guess I just proved your point about reading English where the code might be more straightforward. I can only plead my desire to very briefly explain the query below without getting too far into specifics.
code:
sql = "SELECT p.* FROM payment AS p \
	LEFT JOIN school AS s ON p.schoolID = s.schoolID \
	LEFT JOIN cost AS c ON p.costID = c.costID \
	LEFT JOIN databaseInformation AS d on c.databaseID = d.databaseID
	WHERE s.schoolName LIKE '%school redacted%' && library NOT LIKE '%library also redacted%' \
	&& c.subscriptionStart >= '" + @dateStart.to_formatted_s(:db) + "' \
	&& c.subscriptionEnd <= '" + @dateEnd.to_formatted_s(:db) + "' \
	ORDER BY s.schoolName, s.library, d.databaseName"
					
@payments = Payment.find_by_sql(sql)
If there's some way AR would make this statement go away, I want to know about it!

skidooer posted:

params is your problem here. It's nil. There is no [] method defined for NilClass. If you're doing what I think you are, you want to use a before_filter instead.

skidooer posted:

The odds that you'd ever want to overwrite initialize in either class are extremely low. I can't think of any reason why you'd ever want to, really.

Taking your second statement first, is a controller's initialize method not the best place to put code that I want executed for each action? It seems DRYer than making a separate method and calling that from each action. I also think we've got a slight terminology mismatch here. Anytime I define a function that's already been defined in a base class I'm overriding it, whether I call super() from it or not. Of course if I call super() at the start of my newly declared method I'm really just modifying the existing functionality instead of providing entirely new functionality.

You're saying that params is unavailable/nil in a controller's initialize method? Any specific reason why? If not this is still good to know. My code that it barfed on was something like "if nil != params[:date_from] && nil != params[:date_to]". I was basically setting up some default vars for the actions if those parameters had been provided.

Again, thanks everybody for the constructive comments, I'll be looking forward to lending a hand where I'm qualified to in this forum.

zigb fucked around with this message at 22:47 on Nov 20, 2007

zigb
Mar 21, 2007

poemdexter posted:

I'm writing a little networking site and I can't figure out how to get anything into a table without using a form.
...
Here is the code from my new.rhtml from the group view (REST is awesome)
...
Am I supposed to slap some sort of :creator => logged_in_user.id somewhere?

It makes the most sense to me to put that in your controller instead. So something like:
code:
def new
	@newGroup = Group.new
	@newGroup.attributes= params[:group]
	@newGroup.creator = logged_in_user.id
	@newGroup.save
end
Of course if you use update_attributes instead of attributes=, you'll want to add the creator first.

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