Rails 4 Render Different Depednding on Location of Form Submission - validation

My application allows a user to upload some artwork to a specified campaign through the campaigns 'show' view. This allows me to capture the #campaign.id during the upload for association purposes.
Currently, if an error occurs (validation), it renders action: 'edit'.
I know if I update the render action: 'edit' => to render action: 'show', the basic level task works, but it also messes with the render action when editing the record itself.
If there a way for me to check if the 'update' is being processed through the 'show' view in order for me to render the show action instead of edit?
def update
respond_to do |format|
if #campaign.update(campaign_params)
format.html { redirect_to #campaign, notice: 'Campaign was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #campaign.errors, status: :unprocessable_entity }
end
end
end
Campaign Show View
<button class="btn btn-white" data-toggle="modal" data-target="#new_creative">
<i class="fa fa-plus-square-o"></i> Add New Creative
</button>
<%= render 'remoteforms/add_creative_to_campaign' %>

Related

Update multiple files upload with CarrierWave

I have implemented the "multiple file uploads" in my model just like explained in the documentation of CarrierWave and it's working just fine. My problem is that I can't get the model update working. When I try to add new files it removes the old ones. I'd like to keep both. Here is part of my model and controller:
class Album < ActiveRecord::Base
mount_uploaders :photos, PhotosUploader
end
class AlbumController < ApplicationController
def create
#album = Album.new(album_params)
if #album.save
flash[:success] = 'Album created'
redirect_to #album
else
render 'new'
end
end
def update
#album = Album.find(params[:id])
if #album.update_attributes(album_params)
flash[:success] = 'Album created'
redirect_to #album
else
render 'edit'
end
end
private
def album_params
params.require(:album).permit({ photos: [] })
end
end
I thought about putting the photos in a different model but if I could make it work this way would be better. Any suggestions?
I have the below in my update method to ensure existing images (avatars) uploaded by CarrierWave remain in tact. I have a separate method that allows users to individually delete images.
def update
project_params_holder = project_params
project_params_holder[:avatars] += #project.avatars if project_params_holder[:avatars]
respond_to do |format|
if #project.update(project_params_holder)
format.html { redirect_to #project, notice: 'Project was successfully updated.' }
format.json { render :show, status: :ok, location: #project }
else
format.html { render :edit }
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end

Rails: Submitting an array of child elements

I'm trying to submit a form which is supposed to have an array of child elements. I'm not sure if I have it correctly. Can somebody help me refactor?
I have a couple of models user and item. A userhas_many :items.
The form that sends the information for user and items look like the following -
<%= form_for(#user) do |f| %>
<% f.text_field :name %>
<% f.fields_for :items do |item| %>
<% item.text_field :name %>
<% item.text_field :price %>
<% end %>
<% end %>
I have the following in my controller -
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
#items = #user.items.build(item_params)
if #items.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
end
format.html { redirect_to #user, notice: 'User was successfully created. But there was a problem saving the items.' }
else
format.html { render action: 'new' }
format.json { render json: #userd.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:name)
end
def item_params
params.require(:user).require(:item).permit(:name, :price)
end
When I save the user, only 1 record of items get saved, meaning - the data isn't being passed as an array of objects. How do I get this to work?
It looks like right now you are only ever telling Rails to build one item object. Your form is passing up the two parameters for an item, and in your controller you call build once, so #items is only ever set equal to the single Item returned by build. Unless their are hidden parts of your form you aren't showing, it looks like you're only setting one set of options for a user's items. If your goal is to have an array of many items with identical parameters, the fastest fix would be to just do this within the logic of your create action. There are many ways you could implement that (here is one simple way):
#items = []
x.times { #items << #user.items.build(item_params) }
If you're looking to send a request from the form with multiple unique items, you'll have to add more fields to your form, since currently you are only sending one set of parameters.
There are few corrections to be made in your code.
In your users_controller
def new
#user = User.new
3.times do #this will generate three records of items
#user.items.build
end
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
else
format.html { render action: 'new' }
format.json { render json: #userd.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:name,items_attributes: [:name,price])
end

Ruby render partial on form submit on same page

I am trying to render a partial that I made on top of the current page after a form submit. This should happen in the controller's create method, but I can't seem to figure out if this can be done in Ruby, or if I should just render it using Javascript.
Here is what I have tried so far:
Created a partial in the same folder as the new.html.erb (called _lightbox.html.erb)
The controller render changed to this:
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
BackgroundJob.perform_async(#user.id)
format.html { render :partial=>"lightbox", :layout=>false}
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
I have read up on render, however using the :partial key it simply renders the partial on a new page. I should probably just change the form to use :remote and add the lightbox-esque content with an ajax success, however I was curious as to if this can be done with Ruby on Rails with its rendering functionality.
The code you've displayed here isn't really the problem. It's all in the view.
You need to prevent the default action from form submission, which is to post to the form URL. If the browser posts to that URL, it will render the response. Once you've prevented the default action, you'll then need to submit the form yourself using javascript and set up a callback to deal with the response. That callback should put the html in the place you want it in the page. If any parts of this are unclear, I can expand upon them.

Rails 3 -rendering partials and error "undefined local variable or method"

I have a photos in gallery (PhotosController) and I wanna add to every photo a comments. Into the statement of photos I added a partial for rendering comments + form for adding new comment.
My problem is, that when I send the form with a new comment, so I'll get the rendering error:
**NameError (undefined local variable or method `photo' for #<CommentsController:0x00000100ce0ad0>)**:
This is how looks my code:
views/photos/index.html.erb
<%= render #photos %>
views/photos/_photo.html.erb
<div><%=image_tag photo.photo.url(:thumb)%></div>
<div class="comments_to_photo">
<%= render :partial => 'photos/photo_comments', :locals => { :photo => photo }%>
</div>
photos/photo_comments
<%photo.comments.each do |cmnt|%>
<div><%=cmnt.comment%></div>
<%end%>
<%=form_tag comment_path, :remote => true do %>
<div><%=text_area_tag 'comment[comment]'%></div>
<%=submit_tag%>
<%end%>
controllers/CommentsController
def create
#comment = Comment.new(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to #comment, notice: 'Comment was successfully created.' }
format.js {
render :partial => '/photos/photo_comments', :locals => { :photo => photo } do |page|; page << "$(this).html('abcde');" end
}
else
format.html { render action: "new" }
format.js
end
end
end
I would like to refresh the form and comments statement in the photo, where was added a comment. Could anyone help me, please, how to avoid the error above?
Thank you in advance
EDIT: I added for refresh comments through AJAX the file _photo_comments.js.erb:
$('#photo_comment').html("<%= escape_javascript(render('photos/photo_comments')) %>");
And I get the error
ActionView::Template::Error (stack level too deep):
activesupport (3.2.1) lib/active_support/notifications/instrumenter.rb:23
with tens of this line:
Rendered photos/_photo_comments.js.erb (562.2ms)
and the last one
Completed 500 Internal Server Error in 580ms
What's wrong with rendering? I can't render partial html file from partial JS file?
In your controller you have:
:locals => { :photo => photo }
but the variable photo doesn't exist there. It should be:
:locals => { :photo => #comment.photo }
image_tag photo.photo.url(:thumb) <- Is it what you want to have photo.photo ?

Rails 3.1 ajax:success handling

So Im playing with CoffeeScript, Rails 3.1 all the good stuff. I have a resource with all the usual routes index, show, create, edit, update, destroy.
The index view has a form that uses :remote => true like so:
<%= form_for #todo, :remote => true do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
In the controller for create I have the following:
def create
#todo = Todo.new(params[:todo])
respond_to do |format|
if #todo.save
format.html { redirect_to #todo, notice: 'Todo was successfully created.' }
format.json { render json: #todo, status: :created, location: #todo }
format.js {render json: #todo }
else
format.html { render action: "new" }
format.json { render json: #todo.errors, status: :unprocessable_entity }
end
end
end
Im trying to not use .js.erb views as I would rather handle the JSON returned and do all the fancy appends to the todo list and so on. (It just feels cleaner to me).
In my todos.js.coffee I have used the following:
$(document).ready ->
$("#new_todo")
.bind "ajax:success", (event, data) ->
alert("Ajax SUCCESS!!!")
(Yeah just tyting to open an alert box does not work) I tried loads but just cannot trigger this event. The request does complete successfully and the new todo is added.
Any help with this would be appreciated. Thanks
Started to pour over the rails.js and wondered if any of the ajax: callbacks were being raise.
Turned out they were well the beforeSend and error... hang on... error? How could this be? The creation of the new todo happens successfully, the response is the JSON I expect. But on stepping through the callback code I notice an Invalid label error.
Quick google later brings me to this post http://blog.seqmedia.com/?p=484
Turns out the JSON is being returned as a string, Firbug got that and parsed it correctly so I could check the response. However rails.js and js in general didnt know how to handle the string and threw the above error (rather silently I may say).
The solution was in the respond_to
format.js {render json: #todo, content_type: 'text/json' }
A bit thanks to Trevor Burnham (like the book BTW) for his help and Amy from sequence media whose blog post ultimately gave me the solution.
What is #new_todo? Does an element with that ID exist? Verify that $('#new_todo').length > 0 in your code, and that it's the right element to bind your event handler to.
What is ajax:success? The jQuery API defines an ajaxSuccess event (see the Ajax Events docs), but I've never seen the version with the colon before.

Resources