I have a temp;late with a menu down the lhs that has a search function to restrict the menu options.
Some times the user may search for an option that returns no results.
When the search returns no results I would like to display a flash notice above the search box to communicate this.
In addition to the menu flash i would also like to use flash to communicate the normal messages associated for form operations in the main part of the view such as record save, user logged in etc.
Is it possible to display multiple flash messages on the one view or is there a better way to achieve this?
i had resolved the same scenario using flash with ajax so that i can use id or class selector to update the html in any place in my app.
show flash using ajax
add this in application_helper
def flash_display
response = ""
flash.each do |name, msg|
msg=msg
response = response +
content_tag(:div, msg, :id => "flash_#{name}",:class=>"alert alert-danger") do
"#{msg}".html_safe
end
end
flash.discard
response
end
create js file to show flash messages using id/class selector such as
.....ajax_flash_error.js.erb
<% if type== "User" %>
$('#flash_user').html("<%= escape_javascript raw(flash_display) %>");
<% else %>
$('#common_flash').html("<%= escape_javascript raw(flash_display) %>");
<%end%>
send the flash message from controllers in usual manner such as
users_controller.rb
def create
if user
//do comething
else
respond_to do |format|
flash.now[:error]="You cannot edit this Image"
format.js { render 'shared/ajax_flash_error',:locals=>{:type=>"User"}}
end
end
end
show flash message in layout or any view file....
application.html.erb
<html>
<head></head>
<body>
<div id="common_flash">
<% flash.each do |name, msg| %>
<%= msg%>
<%end%>
</div>
####some other view file,use other flash id
<div id="flash_user">
<% flash.each do |name, msg| %>
<%= msg%>
<%end%>
</div>
</body>
</html>
In this way you can use multiple divs with unique id/class and show flash messages wherever you want throughout application
...HOPE IT HELPS**
Related
Im building sort of a facebook clone, and one of the requirements for the project is being able to "like" posts.
I have the liking down, (im also using devise fwiw on the user authentication). But when I try to flash that a user has already liked a post (since you can't like more than once) nothing happens.
My controller code:
def like
post = Post.find(params[:post_id])
puts post
like = post.likes.new(user_id: current_user.id)
if like.save
#nothing for now
else
flash.now[:alert] = "You have already liked that post"
end
end
It works by being on a users "homepage" and going through all of their posts and having a "like" option on each one. (Liking does work, but figured it was worth noting).
If I just do flash it'll work if I refresh the page, but currently does nothing right now.
The "Like" link looks like this:
<% #posts.each do |post| %>
<p>
<%= post.content %>
</p>
<%= link_to "Like", like_path(#user, post_id: post), remote: true, method: :post %>
<% end %>
In rails there is one gem for ajax call flash messages
Toaster gem
Create one method in application_helper.rb
def custom_bootstrap_flash
flash_messages = []
flash.each do |type, message|
type = 'success' if type == 'notice'
type = 'error' if type == 'alert'
text = "
<script>
$(function () {
toastr.#{type}(\"#{message}\");
});
</script>
"
flash_messages << text.html_safe if message
end
flash_messages.join("\n").html_safe
end
Include it in your layout application.html.erb
<%= custom_bootstrap_flash %>
And in your action.js.erb show toast message using toaster method
toastr.success('Success.')
toastr.error('error')
I hope this what you are looking.
The flash method on rails shows only on successful redirect. If you want to show the message on the same page it would be better to show the message using JS.
I have a navigation bar included in application.html.erb. Because for some pages, such as the signup page, I need to place additional code inside the navigation bar, I have excluded those pages for showing the navigation bar through application.html.erb and instead included it in their respective view pages. See code below.
A problem arises when invalid data is entered in the signup form. The controller method then renders new. However, application.html.erb then doesn't seem to recognize that the current_page is still signup_path, therefore not applying the exception for not showing the navigation bar on that page. As a result when it renders new, the navigation bar is shown twice: once by order of application.html.erb and once by order of the view page itself.
Why, when rendering new on an invalid form entry, does it not see that it's still on signup_path? How should I adjust my code so that it does not show the navigation bar twice in that situation? Is there perhaps a way of including <%= yield special code if any %> in application.html.erb and <% special_code %> <% end special_code %> in the view page that passes this special code to application.html.erb?
In application.html.erb I have:
<% unless current_page?(signup_path) %>
<nav class="banner">
<%= render partial: "shared/header" %>
</nav>
<% end %>
In the view of my signup page:
<nav class="banner">
<%= render partial: "shared/header" %>
Additional code that needs to be within 'nav' for this page
</nav>
Controller method:
def create
#user = User.new(user_params)
if #stakeholder.save
flash[:success] = "A confirmation email has been sent to you."
redirect_to root_url
else
render 'new' ###This is where it goes wrong!
end
end
You can use content_for and yields to create a default in your layout which views can override.
# layouts/application.html.erb:
<% if content_for?(:banner) %>
<%= yield(:banner) %>
<% else %>
<div id="banner">
<h1>This is the default...</h1>
</div>
<% end %>
/users/signup.html.erb:
<%- content_for :banner, flush: true do -%>
<!-- move along, nothing to see here -->
<%- end -%>
The advantage here is that you don't end up turning your layouts into a birds nest of conditionals. You can easily just inject whatever you want into the layout from views.
The cons are that you have to use a stupid hack with a HTML comment to override the block to display nothing since content_for? trims the block. content_for does not play nice with fragment catching either.
addded
I didn't touch on this before unless current_page?(signup_path) does not work as you expect since render 'new' does not magically move you to the new action. In fact the current_path is /users since the form POST's to that url.
It just tells rails to find a template named 'new' and render it.
A corrected version would be:
<% unless controller_name == 'users' && ['new', 'create'].include?( action_name) %>
<nav class="banner">
<%= render partial: "shared/header" %>
</nav>
<% end %>
You are completely right. This is where it goes wrong
render 'new' ###This is where it goes wrong!
Here's what happens
user requests a new action, which renders the new template
user submits the form, thus requesting the create action in your controller
inside your create action you render your new template instead of create when validation fails
So basically user is no longer on the new page, but on the create page with a view rendered from new.
The easiest solution would be to change expectation for the header to both new and create actions, since you redirect on success, so you won't use it otherwise.
I have seen layouts like this in many Rails examples on the web:
...
<main role="main">
<%= render 'layouts/messages' %>
<%= yield %>
</main>
...
The _messages partial is something like this:
<% flash.each do |name, msg| %>
<% if msg.is_a?(String) %>
<%= content_tag :div, msg, :class => "flash_#{name}" %>
<% end %>
<% end %>
I took this content from the rails_layout gem (as seen here), but it is a very common practice to put the partial that renders the flash messages on the application.html.erb default layout file.
In this case, if you fetch content with Ajax and want to replace only the main part, you'll have to do something like this:
def my_controller_action
# ...
if request.xhr?
render :layout => 'other_layout_with_flash_messages'
end
end
Then include the partial with the flash messages again in this other layout, otherwise the flash messages won't show.
My question is: Should the flash messages go inside the layout as they are part of the content?
Additionally: What's the best options for this ajax cases? Should I create another layout?
I'm creating a blog on rails. Everytime a post is created on the new page I want to be back at the index page and see a flash message saying "You post was saved". On the layout I have the following:
<body>
<%= flash.each do |key, value| %>
<p><%= value %></p>
<% end %>
<%= yield %>
</body>
The problem is that I have now on every page (index, new, etc.) curly brackets on the top and I don't know why. Also, instead of just having a message "Your post was saved.". It also appears the following: "{"notice"=>"Your post was saved."}". This is the code for the message hold on the controller (posts_controller.rb):
def create
#post = Post.new(post_params)
if #post.save
redirect_to posts_path
flash[:notice] = "Your post was saved."
else
render "new"
end
end
I'm beginning with Rails, thanks for the help.
See update below for explanation
remove the = in <%= flash.each.... %> Should just be <% flash.each.....%>
<% flash.each do |key, value| %>
<p><%= value %></p>
<% end %>
To keep it simple, when you want your ruby code to render something onto the page, use <%= %>, ex: to show the current time you would use <%= Time.now %>. For other things like settings variables in your view without text rendering on the page, use <% %>.
For example, say I want to assign a variable equal to the current time so I can use it below in the view, I would use <% time = Time.now %> then I can show that time on the page with <%= time %>.
<% time = Time.now %>
<p>The current time is <%= time %>.</p>
New to AJAX and search. I feel like I'm an inch away on this one, but I'm not sure what to fix. Also, my controller looks really hacky to me right now.
At any rate, I'm trying to create a search that allows users to search through blog posts on my page using AJAX. Here are the (relevant parts of the) parts:
posts_controller.rb
def show
#posts = Post.all.reverse
#post = Post.find(params[:id])
#link_num = 10
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to #post }
end
end
def search
#link_num = 10
#posts = Post.all.reverse
#post = Post.find(params[:id])
#The including function returns the search results
#search = Post.first.including(params[:term])
render 'show'
end
What strikes me as "hacky" here is that I repeat all the variable assignments (there are others I didn't show cause they're not relevant). Shouldn't an AJAX call ideally not have to redefine/reload all these variables? Also, I have to pass :id to my search action through a hidden field. This feels weird/wrong to me.
show.html.erb
<h1 class="squeeze">Recent Posts</h1>
<%= form_tag("/search", method: "get", class: "search") do %>
<%= text_field_tag(:term, '', placeholder: "Search posts:") %>
<%= hidden_field_tag(:id, #post.id) %>
<%= submit_tag("Search", class: "btn search_button", remote: true) %>
<% end %>
<% if !#search%>
<ul>
<% #posts.first(#link_num).each do |p| %>
<li>(<%= p.created_at.strftime("%b %d, %Y") %>)</span></li>
<% end %>
<% if #posts.length > #link_num %>
<div class="link_disclaimer">
<h4>---</h4>
<h5><%= "Only showing #{#link_num} most recent posts." %></h5>
<h5>Search to narrow results.</h5>
</div>
<% end %>
</ul>
<% elsif #search.empty? %>
<h3>Term not found!</h3>
<% else %>
<ul>
<% #search.first(#link_num).each do |p| %>
<li>(<%= p.created_at.strftime("%b %d, %Y") %>)</span></li>
<% end %>
<% if #search.length > #link_num %>
<div class="link_disclaimer">
<h4>---</h4>
<h5><%= "Only showing first #{#link_num} relevant hits." %></h5>
<h5>Narrow search for more specific results.</h5>
</div>
<% end %>
</ul>
<% end %>
routes.rb
match '/search', to: 'posts#search'
Currently, the search itself works fine, with three major problems:
The aforementioned messiness of my Controller.
The fact that the whole page reloads. Isn't that the opposite of what AJAX is supposed to do? How can I get it to reload just the list of links?
The URL. It's super messy (i.e "/search?utf8=✓&term=limits&id=11&commit=Search"). I'd ideally have it remain untouched by the search, but if that's not possible, maybe just something like "/search?=". How's that done?
Based on the comment here is basic logic to make the function work(Sorry for no real code as that is too time consuming)
In controller you make a method say "search". The method need an argument which is the phrase to search. It gets the result from db and respond to JSON only with the result.
In template you have a search form.
In JS, you listen the event of user clicking the submit button, catch the characters they write, and handle it to ajax function.
Write Ajax code, preferred using jQuery's ajax(). Basically use ajax() to send the typed characters to controller method in #1 as argument. Then ajax() will get the response(the search result) from server.
Update the result in DOM. You can either add a new div to show search result, or replace current main content div to show result.