I have and index page showing a list of users. What I want is for when I click on a link_to show a certain user in that #users.each form, that shows up the modal (pop ups fine) but gives the data of that user in it as well.
users/index.html.erb
<div class="container">
<% #users.each do |user| %>
<%= link_to user.name, user, { remote: true, "data-target": "#modal-full" } %>
<% end %>
</div>
<%= render 'layouts/modalfull' %>
layouts/_modalfull.html.erb
<div id="modal-full">
<h1 class="name"></h1>
</div>
UsersController
def show
#user = User.find(params[:id])
redirect_to do |format|
format.js // because that would be where the js code would be to push the data to the modal, right?
end
end
Now how it should go in the in the show.js.erb, I have no idea, I'm really not familiar with those stuffs, still new with Rails.
So right now, what I did, will pop-up the modal but wouldn't send the data from the user I clicked on. And I believe that's on the JavaScript side > show.js.erb.
Continued trying different things and came up with this, which made it work.
Which is partially an answer, you'll know why bellow.
users/show.js.erb
$("#modal-full .name").html("<%= #user.name %>");
But if there is any cleaner way to do this, please share.
Because right now, the thing works, it replaces the name but, we see the change being made. So if I clicked on a John, modal would pop up with "John" written on it. Then I close it and click on "Jennifer", modal will pop up with "John" and takes a second to change it to "Jennifer".
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 a Rails 3.2 app that manages students. It has a fairly typical nav bar across the top (Foundation 5) which contains a quick search field. The nav bar is displayed on every page of the site.
If you enter a valid (numeric) student ID into the search field, you simply jump to that student's page. If you enter text or other non-numeric input, you get a flash error asking for valid input. If you enter an id that's not found, you get a flash notice saying it wasn't found. In either of the latter two cases, the controller should just drop you back to whatever page you came from and display the appropriate flash message.
For starters, here's the search field in the view:
<%= form_tag search_students_path, method: 'get' do %>
<div id="nav-search" class="row collapse">
<div id="nav-search-field" class="small-21 columns">
<%= text_field_tag :search, nil, autocomplete: 'off' %>
</div>
<div id="nav-search-icon" class="small-3 columns">
<%= submit_tag ''.html_safe, class: 'button fa fa-search spin', name: 'submit' %>
</div>
</div>
<% end %>
And here's the controller action:
def search
session[:return_to] ||= request.referer
if params[:search].to_i.zero?
flash[:error] = %Q[<i class="fa fa-times fa-fw"></i> Please enter a numeric student ID.].html_safe
redirect_to session.delete(:return_to)
else
id = params[:search].to_i.abs
#student = Student.search(id).first
if #student
redirect_to #student
else
flash[:caution] = %Q[<i class="fa fa-warning fa-fw"></i> Sorry, we couldn't find a student with ID #{id}.].html_safe
redirect_to session.delete(:return_to)
end
end
end
Lastly, here's the code for rendering flash messages in application.html.erb:
<% flash.each do |key, value| %>
<div data-alert class="alert-box cbc-<%= key %>">
<%= value %>
×
</div>
<% end %>
In Chrome and FireFox this works exactly as expected. The flash appears for one request, then disappears. However, in Safari, once the flash comes up it never goes away for that page. So if you get the error flash on the home page, for example, you can refresh all you want. It stays put. You can go to another page, and then come back, and it's still there. The same is true for other pages. Once the flash message has appeared on a given page, it doesn't go away.
Thus my question: how can I get Safari to clear the flash after the first request?
I'm aware of the whole "flash vs. flash.now" issue when rendering pages. But even then, the flash will disappear if you simply refresh. I actually tried flash.now in this case, but then the flash isn't displayed at all in any browser.
Since this appears to be a browser-specific problem, here are some further stats on my system:
Mac OS X 10.9
Safari 7.0
Rails 3.2.16
One final observation. After playing around with this issue in Safari, I noticed that if I clicked my bookmark for http://localhost:3000/, that would clear the flash. Of course, all the navigation links in my site layout contain relative paths, whereas the bookmark is calling a full url.
Anyway, hope that made sense. Thanks in advance for your help!
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.
is there a way to dismiss the standard rails 3.2 forum notice when created a record or logged in with devise? like in twitter-bootstrap there's a cross you can click to dismiss the notice message.
I hope there is a similar way in standard forms.
You asked if there was a simpler way. There is no built in way to do this.... You will need to do something like this:
<% if flash[:notice] %>
<p class="notice"><%= flash[:notice] %></p>
<% end %>
<% if flash[:error] %>
<p class="error"><%= flash[:error] %></p>
<% end %>
In your app/assets/javascripts/flash.js.coffee
$ ->
$(".notice, .error").on("click", (event)->
$(event.target).hide("slow")
)
This will make it where if you click on the .notice or .error, it will hide the slowly (fade out). To this you can include a X icon to close it.
As I understand you not want notice on any particular action so delete <%= notice%> from application.rb file from your layout folder in view.
I hope i understood your question correctly.