public function store($locale = null)
    {
        // Get the default locale
        if (!$locale) {
            $locale = Decoy::defaultLocale();
        }

        // Hydrate the elements collection
        $elements = app('decoy.elements')
            ->localize($locale)
            ->hydrate(true);

        // If the user has customized permissions, filter the elements to only the
        // allowed pages of elements.
        if ($permissions = app('decoy.user')->getPermissionsAttribute()) {
            $elements->onlyPages($permissions->elements);
        }

        // Get all the input such that empty file fields are removed from the input.
        $input = Decoy::filteredInput();

        // Validate the input
        $validator = Validator::make($input, $elements->rules());
        if ($validator->fails()) {
            throw new ValidationFail($validator);
        }

        // Merge the input into the elements and save them.  Key must be converted back
        // from the | delimited format necessitated by PHP
        $elements->asModels()->each(function (Element $el) use ($elements, $input) {

            // Inform the model as to whether the model already exists in the db.
            if ($el->exists = $elements->keyUpdated($el->key)) {
                $el->syncOriginal();
            }

            // Handle images differently, since they get saved in the Images table
            if ($el->type == 'image') {
                return $this->storeImage($el, $input);
            }

            // Empty file fields will have no key as a result of the above filtering
            $key = $el->inputName();
            if (!array_key_exists($key, $input)) {

                // If no new video was uploaded but the preset was changed, re-encode
                if ($el->type == 'video-encoder' && $el->hasDirtyPreset('value')) {
                    $el->encode('value', $el->encodingPresetInputVal('value'));
                }

                return;
            }
            $value = $input[$key];

            // If value is an array, like it would be for the "checkboxes" type, make
            // it a comma delimited string
            if (is_array($value)) {
                $value = implode(',', $value);
            }

            // We're removing the carriage returns because YAML won't include them and
            // all multiline YAML config values were incorrectly being returned as
            // dirty.
            $value = str_replace("\r", '', $value);

            // Check if the model is dirty, manually.  Laravel's performInsert()
            // doesn't do this, thus we must check ourselves.
            if ($value == $el->value) {
                return;
            }

            // If type is a video encoder and the value is empty, delete the row to
            // force the encoding row to also delete.  This is possible because
            // videos cannot have a YAML set default value.
            if (!$value && $el->type == 'video-encoder') {
                return $el->delete();
            }

            // Save it
            $el->value = Request::hasFile($key) ?
                app('upchuck.storage')->moveUpload(Request::file($key)) :
                $value;
            $el->save();
        });

        // Clear the cache
        $elements->clearCache();

        // Redirect back to index
        return Redirect::to(URL::current())->with('success',
            __('decoy::elements.successfully_saved'));
    }