Reputation: 9501
I am trying to show flash message after hitting the update endpoint. I want to keep user on the same page and tell him that the info has been updated. I have turbolinks enabled.
Here is how my action looks like:
def update
@form = Form.find(params[:id])
if @form.update(form_params)
respond_to do |format|
flash.now[:notice] = "Form updated successfully"
format.html { render 'edit' }
format.js { render 'edit' }
# format.html { redirect_to edit_form_path(@form), notice: "Form updated successfully" }
format.json { render json: {message: "Form updated successfully", form: @form} }
end
else
respond_to do |format|
format.html { render 'new'}
format.json { render json: {errors: @form.errors}, status: :unprocessable_entity }
end
end
end
I have tried both flash
and flash.now
both yields no result. If you see the line which is commented out that will redirect to the same page and render the flash.
here is how I am printing the falsh:
<%= notice %>
<%= flash.notice %>
I have used both but they don't seem to work.
From my observation, I can see that Turbolinks hit the format.js
endpoint. Can anyone help me with this?
Edit
This is how my form looks like:
<%= form_with(model: @form, method: 'put') do |f| %>
<!-- name -->
<div class="field">
<label class="label">
From Name
<sup class="is-danger">*</sup>
</label>
<p class="control">
<%= f.text_field :name, class: "input" %>
</p>
<% if @form.errors.any? %>
<p class="help is-danger">
Form name <%= @form.errors[:name].first %>
</p>
<% end %>
</div>
<!-- create button -->
<div class="control">
<%= f.submit class: "button is-primary" %>
</div>
<% end %>
Upvotes: 2
Views: 1619
Reputation: 3676
To signify that you want to submit a form through Ajax, you'll need to put remote: true
on your form element, like so:
<%= form_with model: @form, method: 'put', remote: true do |f| %>
<!-- rest of the form -->
<% end %>
When you click submit, you'll notice the page doesn't change but your Rails logs still show that you pinged your controller. Neat!
Next, you need to figure out what to do with this data. That's what respond_to
is for.
respond_to
will send different responses depending on how the controller was accessed. In your case, the important one is format.js
, but you'll always want to provide a fallback for HTML.
def update
@form = Form.find(params[:id])
if @form.update form_params
respond_to do |format|
flash.now[:notice] = "Form updated successfully"
format.html { redirect_to <SHOW PATH> }
format.js # Will automatically look for update.js.erb
format.json { render json: {message: "Form updated successfully", form: @form} }
end
else
respond_to do |format|
format.html { render :edit }
format.json { render json: {errors: @form.errors}, status: :unprocessable_entity }
end
end
end
end
Note that I made a few code changes.
Now when you submit the form, you should see that nothing changes, the controller is hit, the record is processed, then Rails will look for update.js.erb
. That's where we need to go next!
After you create that file, fill in:
console.log("<%= notice %>");
At this point, verify that you can see the flash in your console after you submit.
You need to abstract the HTML that shows your flash messages out to a partial that I'm going to call _notifications.html.erb
and it'll have this contents:
<!-- _notifications.html.erb -->
<div id="flash">
<% if notice.present? %>
<%= notice %>
<% end %>
</div>
Finally, you have to replace the contents of your flash. Remove everything from update.js.erb
and try this:
$('#flash').replaceWith("<%= j(render 'notifications') %>");
// Or
var flash = document.getElementById('flash'),
flashParent = flash.parentNode;
flashParent.replaceChild("<%= j(render 'notifications') %>", flash);
That's it! Give it a go and let me know if it works.
Upvotes: 1
Reputation: 3676
If the Ajax method is too much of an issue, remove remote: true
and try this:
def update
@form = Form.find(params[:id])
if @form.update form_params
respond_to do |format|
format.html { redirect_to <EDIT PATH>, notice: "Form updated successfully" }
format.json { render json: {message: "Form updated successfully", form: @form} }
end
else
respond_to do |format|
format.html { render :edit }
format.json { render json: {errors: @form.errors}, status: :unprocessable_entity }
end
end
end
end
Then you should have flash data on your page. Try using <%= flash.inspect %>
to verify. Turbolinks should handle most of the Magic here.
The downside being that Turbolinks can give you some issues on mobile. I recommend looking into that if you try this method.
Personally, I prefer the Ajax method. It's a little more work but it gives you more fine-grained control.
Upvotes: 0