Entries Tagged 'Ruby' ↓
August 23rd, 2007 — Ruby
Just noticed something interesting (well not that interesting). Ternary operators in Ruby can be re-written using Boolean operators e.g.
method = object.respond_to?(:foo) ? :foo : :bar
would become…
method = object.respond_to?(:foo) && :foo || :bar
Simply replace ? with && and : with ||
I don’t know if there is any performance gain here, anyone care to investigate?
August 17th, 2007 — Rails, Ruby, Typo
Is anyone else having problems with Typo 4.1 taking ages to process new comments. If anyone has any suggestions I would love to hear them (If you can be bothered to wait for the comment to go through!)
July 30th, 2007 — Mac / OS X, Rails, Rake, Ruby
John Nunemaker posted a handy tip on “setting up autotest to work with Growl”:http://railstips.org/2007/7/23/autotest-growl-pass-fail-notifications
I use this all the time now however I didn’t like the ugly smilies (call me shallow if you like). I used “Wolfgang Bartelme’s”:http://bartelme.at “Smily Devkit”:http://bartelme.at/journal/archive/smiley_devkit to make a couple of PNG’s slightly more pleasing to the eye.
p=. !http://thelucid.com/files/fail.png(Autotest Fail image)!
!http://thelucid.com/files/pending.png(Autotest Pending image)!
!http://thelucid.com/files/pass.png(Autotest Pass image)!
The zip file can be downloaded here: “autotest_images.zip”:http://thelucid.com/files/autotest_images.zip
*Update* 17-08-07: Added ‘pending’ image for RSpec as requested by Aslak Hellesoy
July 25th, 2007 — Ruby
I often need to do a reject! and return the rejected items instead of the modified collection. This saves having to do a select beforehand.
An example of how accomplish this:
options = { :a => 1, :b => 2, :c => 3 }
rejects = Hash[*options.select { |k, v| k == :b && options.delete(k) }.flatten]
assert_equal { :a => 1, :c => 3 }, options
assert_equal { :b => 2 }, rejects
This could be written as a method of the Hash class and an alternative for Array.
For Hash, the code would look something like:
class Hash
def extract!
Hash[*self.select { |k, v| yield(k, v) && self.delete(k) }.flatten]
end
end
options = { :a => 1, :b => 2, :c => 3 }
rejects = options.extract! { |k, v| k == :b }
assert_equal { :a => 1, :c => 3 }, options
assert_equal { :b => 2 }, rejects
If I am missing something obvious in Ruby that accomplishes the same, please leave a comment.
May 16th, 2007 — Ajax, Rails, Rake, Ruby
Following my previous post, below is a modified version of “John Nunemaker’s ‘Renaming RHTML to ERB’”:http://railstips.org/2007/3/4/renaming-rhtml-to-erb to take into account the format in the extension, and handle “the RJS issues I was having”:http://www.thelucid.com/articles/2007/05/16/rails-edge-view-file-extention-functionality-has-changed.
namespace 'views' do
desc 'Renames all .rhtml views to .html.erb, .rjs to .js.rjs, .rxml to .xml.builder and .haml to .html.haml'
task 'rename' do
Dir.glob('app/views/**/[^_]*.rhtml').each do |file|
puts `svn mv #{file} #{file.gsub(/\.rhtml$/, '.html.erb')}`
end
Dir.glob('app/views/**/[^_]*.rjs').each do |file|
puts `svn mv #{file} #{file.gsub(/\.rjs$/, '.js.rjs')}`
end
Dir.glob('app/views/**/[^_]*.rxml').each do |file|
puts `svn mv #{file} #{file.gsub(/\.rxml$/, '.xml.builder')}`
end
Dir.glob('app/views/**/[^_]*.haml').each do |file|
puts `svn mv #{file} #{file.gsub(/\.haml$/, '.html.haml')}`
end
end
end
h4. Update
Added haml conversion.
May 16th, 2007 — Ajax, Rails, Ruby
It seems that on edge revision 6502 and later, the way that view file extensions has changed considerably.
I couldn’t work out why my tests were breaking when doing an xhr request to a new action which had a respond_to block setup for both html and js. It was returning the html instead of the rjs??
It turns out (after tearing my hair out for over three hours) that “Changeset 6499″:http://dev.rubyonrails.org/changeset/6499 changes things in such a way that the normal new.rjs naming will not get picked up on an xhr request, you now need to add the request format to the extension before the template type i.e. new.js.rjs
This seemed a little odd at first but I am guessing it means you could have a new.js.erb file which is pretty cool as you could achieve the same as “Dan Webb’s MinusR plugin”:http://www.danwebb.net/2006/11/17/rjs-minus-r.
What does seem a little odd is that a new.rjs will get picked up if you don’t give a respond_to at-all (I don’t know if this is a “feature” or a bug).
I’m am hoping that this may save someone some time.
July 26th, 2006 — Rails, Ruby, Simply RESTful
UPDATE 15/03/10: The debate continues…
The ideas in this article came about whilst I was test-driving the Simply RESTful plugin following DHH’s RailsConf keynote on the subject.
The philosophy
The first thing I came across whilst experimenting with Simply RESTful (which is great by the way), was that there is no real way of deleting items with javascript disabled. Since I am currently working on a project that needs to function on a variety of mobile devices, this instantly caused me concern.
I could think of a few ways to hack around this limitation, however I was sure there had to be a better way, hence this article. I wanted to keep the current javascript functionality but in addition have a clean non-javascript fallback.
Consider the following:
| CRUD |
Form (GET request) |
POST action |
| (C)reate |
/products/new |
create |
| (R)ead |
/products/24 |
n/a |
| (U)pdate |
/products/24/edit |
update |
| (D)elete |
- |
destroy |
There are three “state changing” actions in CRUD, they are the ‘create’, ‘update’ and ‘delete’. You will notice from the table above that all three have a POST action1, however only two have GET actions… why is this?
Now, you see that dash in the second column… that’s “the missing action”. There is no good reason why our ‘destroy’ action shouldn’t have a corresponding form action (GET request) also. Let me explain myself…
1 The HTTP actions are PUT, POST and DELETE, however in this implementation (due to the limitations of HTML) they are all technically POST’s.
Putting it into practice
So we give ‘destroy’ it’s missing action which will act as a confirmation of our post… and what shall we call this missing action? …why let’s call it delete.
If we fill in this missing piece in our RESTful Rails puzzle, all becomes clear:
| CRUD |
Form (GET request) |
POST action |
| (C)reate |
/products/new |
create |
| (R)ead |
/products/24 |
n/a |
| (U)pdate |
/products/24/edit |
update |
| (D)elete |
/products/24/delete |
destroy |
Our routes would look something like:
map.resource :product, :member => { :delete => :get }
In our controller would be:
def delete
@product = Product.find(params[:id])
end
def destroy
Product.find(params[:id]).destroy if request.delete?
redirect_to product_url
end
Our delete.rhtml would look like this:
<h1>Are you sure you wish to delete ?</h1>
Slight complication…
Update (13 Oct 2007): This has been fixed in more recent versions or Rails.
Now comes the slight complication… we want the javascript POST to /projects/24 to function as normal, however if javascript is disabled we want to request /projects/24;delete.
Wouldn’t it be nice if you could specify a fallback (non-javascript) href in the link_to helper, something that I’ve pondered with on many occasions. Unfortunately the link_to helper doesn’t let you override the href attribute (currently it adds a second one instead), until now.
Enter iq_noscript_friendly plugin which fixes this shortfall (I also have this as a Rails patch however the ticketing system on Trac is currently broken).
Install the plugin using:
./script/plugin install http://svn.soniciq.com/public/rails/plugins/iq_noscript_friendly/
In our listing view (index.rhtml) we are now able to do the following:
link_to 'Delete', product_url(product),
:confirm => 'Are you sure?',
:method => 'delete',
:href => delete_product_url(product)
Ideally you would just give the link a class of “delete” and use unobtrusive javascript to make it do the delete request.
Beautiful.
Summary
By adding “the missing action”, we are able to POST as usual (using javascript) to ‘destroy’ but gracefully fallback to our ‘delete’ form when javascript is not available. Besides, why shouldn’t ‘destroy’ get it’s own form action… ‘create’ has ‘new’ and ‘update’ has ‘edit’?
Now to make this whole thing even better, lets make it part of the convention. ‘delete’ should default to GET and therefore negate the need for :member => { :delete => :get } in our routes.rb… DHH?
I would love to hear peoples comments on this technique as I’m using it for everything now and it works a treat.
Com’on… use “the missing action”, be kind to those without javascript, and lets make it the convention!
Rock on RESTfulness.