Adding pictures to a story

August 2, 2007

First step, before worrying about how to upload and store picture files, is to check that i can go back and forth between the edit_story and new_picture pages without losing the in-progress story. I’m going to do this by making the new_picture method take a story object (it can’t just take an id as the story won’t have been saved to the db so can’t be retrieved from the db via id), and return a story object as well. First i’d better have a form view for new_picture.

views/newspipe/new_picture.rhtml

<%= render :partial => ‘save_page’ %>
<%= render :partial => ‘login_manager’ %>

<h1>Add a picture</h1>

<% form_tag :action => ‘create_picture’, :story => @story %>
<p><label for=”picture_title”>Title</label><br/>
<%= text_field ‘picture, ‘title’ %></p><span>Required</span>

<p><label for=”picture_summary”>Summary</label><br />
<%= text_field ‘picture’, ‘summary’ %>

<p><label for=”picture_tags”>Tags</label><br/>
<%= text_field ‘picture’, ‘tags’ %></p>

<%= submit_tag ‘Submit %>
<% end %>

<%= link_to ‘Back’, :action => ‘edit_story’, :story => @story %>

This is only worrying about title, summary and tags for the moment. One thing i realised is that it can’t go back to ‘edit_story’ when they submit, it needs to go to ‘create_picture’, which sets some details and saves to the db, before redirecting to edit_story.

So, next stage is the new_picture and create_picture methods in newspipe_controller.

One problem already…how can we assign a story id to a picture if we’ve not saved the story to the db yet? Maybe we can add it to the story with @story << picture. I’ll try that.

To test this is working, i’ll display the title of the story on the ‘new_picture’ view. Ok, done that, haven’t tested yet though.

Next is the create_story method: this needs to add the picture to the story’s pictures (which as suggested above might be doomed to failure) and add the user_id, which i’ll get out of the session.

First attempt:

def create_picture
@story = params[:story]
@picture = @story.create(params[:picture])
@picture.user_id = session[:user].id
if @picture.save
flash[:notice] = “Added your picture.”
else
flash[:notice] = “Sorry, your picture was not able to be saved.”
end
redirect_to :action => “edit_story”, :story => @story
end

Now, let’s see if that all worked…..it’s taking ages to load a screen up, don’t know why…

After a couple of minor tweaks (missing quotes for example) i can go to the add picture screen. However, when i hit submit, nothing happens. Added a bit of output code (using the flash store) – the story isn’t getting through to the ‘new_picture’ method. hmmm.

The more i think about this ‘passing an unsaved story around’ plan the dirtier it seems. I have a couple of alternatives –

a) Save the story to the db before adding a picture. This is going to raise problems with validity checks, eg for the title of the story (which is required), unless i give it a default value of ‘untitled story’ when the page loads up. It also just seems wrong – the story shouldn’t be saved until the user tells the system to save it by submitting. This might make it easier to edit the story afterwards though – in new_story i can save session[:user] into the db and then make sure that the current user is the same as the saved user before allowing anyone to edit the story.

b ) do it in a different way altogether.

Ah, now here’s an idea – i can save incomplete stories to the db, perhaps using a boolean field called ‘complete’. The story list will be modified to only show complete stories, and i can also, for any user, show all of the stories they have created which are incomplete, ie ‘drafts’. I can also do stuff like autosave a story every five minutes. This seems like a good idea, and will solve the problem above: i can save the story as soon as it’s created, and when the user hits ‘add picture’, i can save the story again and pass its id across. Going to try to set that up now.

(as an aside, adding the ‘complete’ field to the db taught me some good lessons about migrating using rake, and rolling back, eg with adding columns and removing them again . Nice reference page here)

So – changes to the code: need to pass over the story_id when calling add_picture, and when we submit a picture, we need to go back to the story with that id. Should be just like adding a story to an article. Actually not quite- we need to save the story before going over to the picture.

OK – fixed it so you can add a story (without worrying about pictures for now) – this took a bit of rewriting as i changed the way that edit_story and create_story worked: we either retrieve a story or we make a new one and add it to the stories of the current article.

def edit_story
#if we’re given a story id, then we need to just retrieve that story (or raise an error if we can’t find it)
if params[:id]
@story = Story.find(params[:id])
#if we’re not given an id, we need to make a new one. we should have been
#given an article to add it to as well

else
@article = Article.find(:first, :conditions => [“id = ?”, params[:article_id] ])
@story = Story.new
@article.stories << @story
end
@story.added_at = DateTime.now.to_s
@story.user_id = session[:user].id
@story.title = “Untitled story” unless @story.title
@story.complete = 0
if @story.save
flash[:notice] = “Saved story draft.”
else
flash[:notice] = “Sorry, your story draft was not able to be saved.”
end
end

Create also works a bit differently – now, we get a story id and update its params with the values from the form. This is easy in rails, using the update_attributes method: after doing that we set the “completed” to true and save.

def create_story
@story = Story.find(params[:id])
#need to update @story with the contents of the fields
@story.update_attributes(params[:story])
@story.added_at = DateTime.now.to_s
@story.user_id = session[:user].id
@story.points = 1
@story.complete = 1
if @story.save
flash[:notice] = “Saved completed story.”
else
flash[:notice] = “Sorry, your story was not able to be saved.”
end
redirect_to :action => “show”, :id => @story.article_id
end

To test that edit is working properly, i’m going to add the option to edit an existing story, but only if it was saved by the current user. This change will go in the _story_list partial – I added the following lines:

<% if story.user_id == session[:user].id %>
<span><%= link_to “Edit this story”, :action => “edit_story”, :id => story %></span>
<% end %>

Ok, that seems to work though it could do with a different style.

And, for a change, edit_story seems to be working fine. I tested adding a story and also going back to revise an existing story. Next, check you can swap users and only be able to change stories added by that user…aha! The code i added to the partial, to say “edit this story” wasn’t quite clever enough – it got caught out because session[:user] was equal to nil. Need to just make a slight change to cope with that… in the if statement, before comparing the story’s user_id with the session, user, i checked that there is a value for session[:user]:

<% if session[:user] && story.user_id == session[:user].id %>

If there isn’t, lazy evaluation means that we won’t try to get the id of the nonexistent user.

OK – so, finally, lets see if add_picture is working!

hmmm…clicking ‘add_picture’ saved the story and went back to the show page for that story! What’s going on there… let’s try and follow it through:

In edit_story.rhtml, the button code looks like this:
<%= button_to “Add a picture”, :action => “new_picture”, :id => @story.id %>

So, that calls new_picture and passes through the id of the story, as :id.

The new_picture controller code looks like this:
def new_picture
@story = Story.find(params[:id])
flash[:notice] = “Can’t find story.” unless @story
end

All this does is create an instance variable called @story for the view to reference. The view has a form which does the following when submitted:
<% form_tag :action => ‘create_picture’, :story_id => @story %>

This calls the ‘create_picture’ action, passing through :story_id. But, we’re not even getting to this stage, we’re going back to ‘show’ when we hit the ‘add picture’ button in ‘edit_story’.

I need to do some proper debugging.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: