Showing posts with label code. Show all posts
Showing posts with label code. Show all posts

Thursday, May 22, 2008

make_resourceful and odd controller names

I've been debugging make_resourceful to try to figure out why it fails to generate an index action for a controller named NewsController. After a couple of hours I found the now slightly obvious reason in lib/resourceful/default/accessors.rb...

The singular? method returns true for "News".

A simple solution would be to define singular? in your controller and let it return false.

Example:

class NewsController < ApplicationController
def singular?; false end

make_resourceful do
actions :all
end
end


See also: More on odd controller names

Tuesday, May 20, 2008

response.should have_tag problems

I use "integrate_views" to combine controller and view specs. The thing I discovered just now is that if you have nested describes, you have to place "integrate_views" inside the inner describe or "have_tag" won't work.

The error you typically get otherwise (even when the element exists) is:
Expected at least 1 element matching "div#content", found 0.

For this particular project I'm using RSpec 1.1.3.

Monday, March 31, 2008

In Place Editor using Scriptaculous and Prototype in Rails 2.0

I've been using the scriptaculous InPlaceEditor and thought I would share some useful snippets.

The code is setup to save on blur and being able to handle empty fields.

The creation script:

var inplace_editor_edit_hint = 'Click to edit...';

function createInplaceEditor(field, update_path, highlightcolor,
highlightendcolor, width)
{
fillIfEmpty($(field));

new Ajax.InPlaceEditor(field, update_path, {
highlightcolor: highlightcolor,
highlightendcolor: highlightendcolor,
okButton: false,
cancelLink: false,
submitOnBlur: true,
cols: width,
callback: function(form) {
input_field = form.elements[0];

// This is to ensure we don't save the edit hint if
// the user accidentally clicked an empty field
if(input_field.value == inplace_editor_edit_hint)
input_field.value = '';

return Form.serialize(form);
},
onComplete: function(transport, element)
{
fillIfEmpty(element);

if(transport.statusText != "Internal Server Error")
onEditorSuccess(); // cb

new Effect.Highlight(element, {
startcolor: this.options.highlightcolor,
endcolor: this.options.highlightendcolor
});
},
onFailure: function(element, transport) {
onEditorFailure(transport.responseText); // cb
}
});
}

function fillIfEmpty(element)
{
if(element.innerHTML == '')
element.innerHTML = inplace_editor_edit_hint;
}


In the view I have a bit of script that binds the callbacks for success and failure.

The validation errors is displayed in the error notice, this isn't exactly ideal, but works as an example of how to handle validation.


function onEditorSuccess()
{
$('error').innerHTML = '';
$('notice').innerHTML = 'Model was successfully updated.';
}

function onEditorFailure(response)
{
response = response.evalJSON();

var lines = new Array();

for(var i = 0; i < response.length; i++)
lines.push(response[i][0] + ' ' + response[i][1]);

$('notice').innerHTML = '';
$('error').innerHTML = 'Error: ' + lines.join('. ')
}


The controller code looks something like this:

def update_field
model = Model.find(params[:id])
if model.update_attributes(field_to_update => params[:value])
render :text => params[:value]
else
render :text => model.errors.to_json, :status => 500
end
end

private

def field_to_update
params[:editorId].split('_')[1]
end


And finally I create them using something like this:


<p id="prefix_title"><%= model.title %></p>
<script type="text/javascript">
createInplaceEditor("prefix_title", '/path/to/action',
"#FFFFFF", "#AAAAAA", 10);
</script>


Though I recommend wrapping it in a helper to keep it nice and DRY...

Tuesday, February 5, 2008

HABTM issue with Rails 2.0.2 and SQLite3

When using SQLite3 with rails you must make sure not to add an id column to your join tables (probably a good idea in any case).

The error I got when I did have an id column where something like this:

SQL logic error or missing database: INSERT INTO
podcasts_tags("podcast_id", "id", "tag_id") VALUES (3, 3, 1)


To avoid this, make sure you include :id => false when creating the join table:

create_table :podcast_tags, :id => false do |t|
t.integer :podcast_id, :null => false
t.integer :tag_id, :null => false
end

Thursday, November 8, 2007

Degrading link_to_remote

I've been learning RubyOnRails and I noticed that the 'link_to_remote' helper didn't degrade gracefully...

Here's the fix I used (Inspired by this blog post).

(in helpers/application_helper.rb)

def link_to_remote(name, options = {}, html_options = {})
unless html_options[:href]
html_options[:href] = url_for(options[:url])
end

link_to_function(name, remote_function(options),
html_options)
end

Just keep in mind that this uses a HTTP GET when javascript is disabled. A HTTP GET should not have side effects. I can't think of a good way to do a HTTP POST from a link (trigger a form-post) without using javascript.

Thursday, July 19, 2007

TinyMCE inside of an ASP.NET Ajax UpdatePanel

Yesterday I went hunting for information on how to get the
web WYSIWYG editor TinyMCE to work inside of an ASP.NET UpdatePanel.

There are a few solutions for this on the web, nothing near as complete as Jesper Lind's post (Swedish), but even that failed to work. I replied to the post asking if he had some simple example that he could show and as a result we now have this complete example.

Here is a VB.NET version of Jesper's example I made when adapting the code to work in my VB.NET project at work.

Update: 2007-07-30
Having had some experience with using this I'd highly recommend that you use webservices as the editors inside of any non-trivial updatepanel setup can become quite slow to reload.

To use TinyMCE on an Ajax form, load TinyMCE at page load as usual, but run "tinyMce.updateContent(text-area-id)" after you load text into the textareas so that it is displayed. If you have any problems with IE6 not updating the content, check this thread out. Also run tinyMCE.triggerSave(true, true) before saving so that TinyMCE copies text back from the editors.

Tuesday, May 15, 2007

Neat session state trick

Just thought I'd share a neat little bit of code for handling session state in ASP.NET.

The trick is to create a class that keeps it's own sessionstate, like this:

public class CustomerSession
{
private string mName = "";
private string mTelephone = "";

// To enshure unique session key
private static string mGuid = "PlaceGUIDHere";

public string Name
{
get { return mName; }
set { mName = value; }
}

public string Telephone
{
get { return mTelephone; }
set { mTelephone = value; }
}

private CustomerSession() { }

public static CustomerSession GetInstance(HttpSessionState session)
{
CustomerSession o = (CustomerSession)session[mGuid];
if(o == null) {
o = new CustomerSession();
session[mGuid] = o;
}

return o;
}
}

Then you can save data in session like this:

protected void btnSave_Click(object sender, EventArgs e)
{
CustomerSession data = CustomerSession.GetInstance(Session);
data.Name = txtName.Text;
data.Telephone = txtTelephone.Text;
}


I heard about this in .NET Rocks! episode 82 where Richard Hale Shaw where speaking of his way of storing session state in a safe way. It's at about 54 minutes into the podcast episode if you want to check it out for yourself =)

Thursday, April 5, 2007

Weeks of .NET

This last month have been spent coding in .NET (mostly VB.NET) at my full time practice at Avancit AB. I thought I would share a few things I've come across in the projects I've been working on during that time.

T-SQL
I had a problem where I needed to get all mail addresses of all groups in a company except those in the current group. This was solved by the SP shown below:

ALTER PROCEDURE [dbo].[sp_GetMailAddressesByCompany]
(
@intCompID INT,
@excludeGroupID INT
)
AS
BEGIN
— Get all addresses in company that are NOT in the excluded group
SELECT addr.* FROM tblMailAddresses addr
INNER JOIN tblMailGroupsToAddresses con
ON con.intMailAddressID = addr.intMailAddressID
WHERE addr.intCompID = @intCompID
AND addr.intMailAddressID NOT IN
(
— Get all addresses in the excluded group
SELECT addr.intMailAddressID FROM tblMailAddresses addr
JOIN tblMailGroupsToAddresses con
ON con.intMailAddressID = addr.intMailAddressID
WHERE con.intMailGroupID = @excludeGroupID
)
END


BCP versus SqlBulkCopy
Another problem was where we had an application that needed to push tables from a client to a server effectively. The current version at the time used BCP which was run from a batch process and sometimes (but very rarely) failed.

I started to look around and I found that people where replacing BCP with SQLBulkLoad. I suggested we'd try it and we successfully implemented the transfer using it. As the whole process now took place inside the .NET application it was simple to setup a better error handling than was possible with BCP.

Macros
As for productivity, I've started to look into using macros in VS2005. The first macro I installed was one that reversed assignments. I know there are tools that do this, I think ReSharper has this ability, but I don't have it yet so a macro works just as good. You can find this macro at: http://www.codeproject.com/useritems/macroswapassignments.asp

DNR
Anyone still not listening to DotNetRocks are missing some great stuff. As I'm on a train or a bus for 3 hours a day I've listened to quite a few episodes in the last few weeks (1 to 40). Even the early episodes are great, they give a good insight into why things are the way they are and what is new in .NET 2.0 (as I started with 2.0, I don't have much of a reference as to the differences compared to 1.1).

TDD
Next week we're starting a project that will use TDD (Test Driven Development) for the first time within Avancit. It will be lots of fun and I'll probably write how that goes here later.