concerto/concerto — pull request #718 by mfrederickson (2013-09-13 23:16:40+00:00)
Title: Graphics preview 622

This addresses issue #622.

This was not as simple as the ticker preview where you simply pass the preview method the html string and it returns a sanitized version of it for you to display.

In order to implement a preview method on the graphic class, the actual file had to be uploaded to the server first. So I used Brian's suggested method of using the jquery.iframe-transport plugin and wired it up to the "Choose File" button's change event [graphics.js]. But where should it send the file?

I chose to send the file to the media table, because 1) most of the time they will submit what they're previewing, 2) it's going to end up there anyway (if they do submit), 3) why just write it to a temp file when there's already code to work with media items?, 4) leverage the caching already occurring in the render method, and 5) lack of alternative architectural guidance.

So when they click the "Choose File" button, the file gets sent via ajax to the media#create where it is created with a key of 'preview' and an attachable_id of zero and an attachable_type of 'Content'. The media id is then returned as the ajax result.

The ajax complete handler takes the media id, gets the width of the preview area and passes that to the graphics preview method (much like the ticker handles it). The graphics preview method constructs an image tag to use to preview the graphic and returns the image tag html which is then loaded into the preview area, and the dom fetches the image.

When the media_id comes back, the ajax complete handler also stuffs it into a hidden form field which is uploaded when the form is posted. This is how we know what media to attach to the new graphic content. And since the jquery.iframe-transport resets the file field, the file will never get uploaded a second time when the form is submitted.

For files that get previewed but never saved as content there is a delayed job scheduled in the cron.rb that calls the Media#cleanup_previews method that removes preview media that is more than 15 minutes old.

This also accommodates displaying the preview when form submission fails due to validation errors such as lack of a name-- which the ticker preview currently does not handle.

I also placed the jquery plugin script into the vendor/assets/javascripts folder-- isn't that where the third party js is supposed to go?

Things I'm not quite satisfied with:
1. Skipping the CSRF check on the media create for the ajax call.
2. Unsure if someone can see media that they shouldn't.
3. An extra trip for the preview (but this is to reuse existing code in the content's render method).
4. Not sure how this is going to work with the PDFs and PPTs, etc.
5. I feel like there should be some tests added for this, but 1) I'm not quite sure what they should be, and 2) I don't want to waste the effort doing that if all this work gets rejected.

Overall, it works, and I hope it is satisfactory for what @brzaik needed specified in #622. I know Brian said he had already worked up the file upload piece, but it wasn't in the repo, and I needed it to be able to test the rest of the solution, so I had to implement the form stuff.