Rails - Dynamically Login People - javascript

I have a rails app and when user clicks to login button on header a bootstrap popup modal opens with a form, asks for user email and password. When user types and presses enter, I use window.location.reload(); and the button login turns in to a button with a text says "Welcome <%= current_user.name %>"
What I want to do is, instead of using window location reload, can I update this dynamically?
Here is my sessions#create action
def create
user = User.find_by(email: params[:session][:email].downcase)
respond_to do |format|
if user && user.authenticate(params[:session][:password])
if user.activated?
log_in user
params[:session][:remember_me] == '1' ? remember(user) : forget(user)
format.html { redirect_back_or user }
flash[:notice] = t('flash.sessions.create.success.html')
format.js #here I should do smth
else
format.html { redirect_to root_url }
format.json { render json: {email:['Account not activated. Check your email for the activation link.']} , status: :unprocessable_entity}
format.js { render json: {email:['Account not activated. Check your email for the activation link.']}, status: :unprocessable_entity }
end
then the create.js.erb
// close modal
$('#login-dialog').fadeToggle();
// clear form input elements
// todo/note: handle textarea, select, etc
$('form input[type="text"]').val('');
//Clear previous errors
$('.form-group.has-error').each(function(){
$('.help-block').html('');
$('.form-group').removeClass('has-error');
});
window.location.reload(); #here I am reloading the page then I can see login button disappears and new button saying Welcome Billy appears.
So how can I do that without reloading the window.
Thank you
EDIT
The thing is, I have also signup modal which user can click to open and these modal codes are in header.html.erb, when I render the page as you suggested it gives an error for sign up form;
<% modal ||= false %>
<% remote = modal ? true : false %>
<%= form_for(#user, remote: modal, :html => {role: :form, 'data-model' => 'user'}) do |f| %>
<div class="form-group">
<%= f.label :name, t('header.nameSurname') %>
<span class="help"></span>
<%= f.text_field :name, class: 'form-control' %>
<span class="help-block"></span>
</div>
<div class="form-group">
<%= f.label :username, t('header.username') %>
<span class="help"></span>
<%= f.text_field :username, class: 'form-control' %>
<span class="help-block"></span>
</div>
....
because of #user variable, if I change it to User.new is it ok?, would it create problem?.
I also have 3 different header partials. I normally render them in application.html.erb as;
<div id="render_main">
<% if #header_main %>
<%= render 'layouts/header_main' %> <!--Header comes here-->
<% elsif #header_listing %>
<%= render 'layouts/header_listing' %> <!--Header comes here-->
<% else %>
<%= render 'layouts/header' %>
<% end %>
</div>
But then in create.js.erb;
// close modal
$('#login-dialog').fadeToggle();
// clear form input elements
// todo/note: handle textarea, select, etc
$('form input[type="text"]').val('');
//Clear previous errors
$('.form-group.has-error').each(function(){
$('.help-block').html('');
$('.form-group').removeClass('has-error');
});
//window.location.reload();
<% if #header_main %>
$('#render_main').html('<%= j render "layouts/header_main"%>')
<% elsif #header_listing %>
$('#render_main').html('<%= j render "layouts/header_listing"%>')
<% else %>
$('#render_main').html('<%= j render "layouts/header"%>')
<% end %>
as I render it can not find #header_main variable I believe, so It does not work as it should be. How can I fix this?.
Main controller;
before_action :show_main_header, only: [:home]
def show_main_header
#header_main = true
end
Considering user login, from main controller home action. But it is probably because I actually run from session#create action. how can I fix it?
EDIT
firstly, thank you Rodrigo,
I have written a function to hold last action;
def location_action_name
if !logged_in?
url = Rails.application.routes.recognize_path(request.referrer)
#last_action = url[:action]
end
end
Then I write to create.js.erb;
<% if (#last_action == "home") %>
$('#render_main').html('<%= j render "layouts/header_main"%>')
<% elsif (#last_action == "listings") %>
$('#render_main').html('<%= j render "layouts/header_listing"%>')
<% else %>
$('#render_main').html('<%= j render "layouts/header"%>')
<% end %>
and worked! in case anyone wonders..

Let's say that you have an partial view for render the header (app/views/shared/_header.html.erb), what you need to do is rerender this partial and replace the header html:
create.js.erb
// window.location.reload();
$('#header-container').html('<%= j render "shared/header"%>')
EDIT:
If the #header_main and #header_listing variables are used to render the header partial, you'll need to instantiate them in your sessions#create action.
To do this, add the show_main_header filter to SessionsController too.

Related

Rails 5, simple javascript with form submit

I am hoping someone can help me here. Been at this for a few hours, but can't seem to figure out why my Javascript is not working on my simple form. I'm simply trying to display comments using the ajax call. I have gem 'jquery-rails', and required jquery, and jquery_ujs in my application.js file. Here's the code I have so far:
I have a Joy model that has_many comments.
<% #joys.each do |joy| %>
<ul id="comments-<%= joy.id %>">
<% joy.comments.where(void:'f').each do |comment| %>
<li><%= comment.body %></li>
<% end %>
</ul>
<%= form_with(model: [ joy.user, joy, joy.comments.build ], data:{ "js-comments-#{joy.id}" => true}) do |f| %>
<%= f.text_area :body, :class=>'form-control', :required=>'true' %>
<%= f.submit "Post Comment" %>
<% end %>
<script>
$(document).ready(function() {
$('[data-js-comments-<%= joy.id %>]').on("ajax:success", function(event, data, status, xhr){
$('#comments-<%=joy.id%>').append(xhr.responseText);
});
});
</script>
<% end %>
In my Comment controller, in my 'create' action, I have:
if #comment.save
render partial: "comment", locals: {comment: #comment}
end
In my Comment views, I created a partial, called _comment.html.erb:
<li>
<%= comment.body %>
</li>
So, now when I enter a comment, and click 'Post Comment', it correctly saves my Comment, but it does not ajax load the comment into list. Furthermore, the form does not refresh either. The text remains in the text box. It is not only until after I refresh the page when my comment shows up in the list. Anyone with any thoughts on what I'm missing or doing wrong???
Your help is greatly appreciated in advance.
form_with it's a remote form, you dont need that block <script>..</script>.
Just use create.js.erb then use jquery to append new comment.
And if you want to check if your message was created successfully, you can add a #status value in your controller.
//comments_controller.rb
def create
...
if #comment.save
#status = "success"
else
#status = "failed"
end
...
end
//create.js.erb - for example
$("#yourCommentList").append('<%= j( render partial: 'comments/comment', locals: #comment ) %>');
<% if #status == "success" %>
$("body").append(...your notification...)
...
<% else %>
...
<% end %>

Rails-jQuery Why do I have to click twice for jQuery effect to show?

I am using Rails 4.1.1 Why do I have to click twice for jQuery effect to show?
I have been Googling but I cannot find any solutions, not sure if there's something wrong with my jQuery code or....
When I click "Submit" for the first time, the effect didn't appear but the POST action is already called, when I click for the second time, the effect appeared and the POST action is called.
Please check below my create.js.erb, users_controller.rb, new.html.erb
create.js.erb
function isValidEmailAddress(emailAddress) {
var pattern = new RegExp(/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))#((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i);
return pattern.test(emailAddress);
};
$("form").submit(function( event ) {
var email = $("input#user_email").val();
if (email == "") {
$("h1").text( "Email cannot be empty" ).show().fadeOut( 3000 );
return;
} else if (!isValidEmailAddress(email)) {
$("h1").text( "Email address is not valid" ).show().fadeOut( 3000 );
}else {
$("h1").text( "Correct email address" ).show();
}
event.preventDefault();
});
new.html.erb
<%= form_for #user, remote: true do |f| %>
<p>
<%= f.text_field :email %>
</p>
<p>
<%= f.submit :Submit %>
</p>
<% end %>
<h1></h1>
<% #users.each do |user| %>
<tr>
<li><%= user.email %></li>
</tr>
<% end %>
users_controller.rb
class UsersController < ApplicationController
def new
#users = User.all
#user = User.new
end
def create
#user = User.new(user_params)
respond_to do |format|
format.html { redirect_to '/' }
format.js
end
#user.save
end
private
def user_params
params.require(:user).permit(:email)
end
end
Turbo links might be causing this issue -try disabling turbo links in your app , that has worked for me In the past when I've had a similar problem
You're getting the process wrong. When you submit a remote form in Rails, the app sends an AJAX request to the create action and then evals the received js code (from your create.js.erb). So first time you click the button, nothing happens.
The js view is not the place to handle validations, you should put that somewhere in your assets/javascripts. The js view is a place for updating the html view of the page with the form (e.g. adding records to the list, showing received errors, reseting the form).

Variable inaccessible to JS when in partial

I have a signup form with JS validation. It works fine when the signup form is directly in the html. However, when the signup form is accessed via a partial, it fails to read the variables from the form. In that case the form always displays the error 'Please type in your name.'
JS:
$('.js-sign-up-submit').click(function(event) {
event.preventDefault ? event.preventDefault() : event.returnValue = false;
var nameFirst = $('.js-user-name-first').val();
if (!nameFirst) {
$('.js-sign-up-error').text('Please type in your name.');
}
...
});
html layout:
<body>
<%= render :partial => "/shared/header" %>
<% if notice %>
<p class="alert alert-notice"><%= notice %></p>
<% end %>
<% if alert %>
<p class="alert alert-error"><%= alert %></p>
<% end %>
<%= yield %>
<%= render :partial => "/shared/login_form" %>
<%= render :partial => "/shared/sign_up_form" %>
<%= render :partial => "/shared/password_reset_form" %>
<%= render :partial => "/shared/footer" %>
<%= javascript_include_tag "home" %>
</body>
Turns out the partial for the signup form was called in two places: in the layout file (as shown above) AND in the shared header file. So the JS was validating the signup form linked to in the layout which was not the one filled out by the user, hence failing to register the inputted text. We simply removed the duplicate signup partial in the header and it now works fine.

Why does my js.erb file only run in one of these situations?

I have the following action on my controller for a Comment:
def create
#comment = comment.new(params[:comment])
#comment.replyable_type = params[:replyable_type]
#comment.replyable_id = params[:replyable_id]
#comment.user = current_user
respond_to do |format|
format.html do
# Removed
end
format.js do
#comment.save
end
end
end
and the following create.js.erb file for when it gets called by a remote form:
console.log('It did run');
<% if #comment.errors.any? %>
<% #comment.errors.full_messages.each do |msg| %>
console.log('<%= javascript_escape(msg) %>');
<% end %>
<% else %>
comment = "<%= escape_javascript render #comment %>";
<% if #comment.replyable_type == 'Comment' %>
$('#comment-<%= #comment.id %> > .replies').prepend(comment));
<% else %>
$('.comments').prepend(comment);
<% end %>
// removed
<% end %>
Along with the following form partial:
<%= form_for(Comment.new, url: comments_path, remote: true) do |f| %>
<div class="comment-form" id="comment-<%= replyable_type %>-<%= replyable_id %>">
<%= f.text_area :content, cols: 60, rows: 5 %>
<%= hidden_field_tag :replyable_id, replyable_id %>
<%= hidden_field_tag :replyable_type, replyable_type %>
<%= f.submit 'Send Comment', class: 'btn btn-primary' %>
</div>
<% end %>
replyable is a polymorphic association, which can be either a Post or a Comment object. When I submit a copy of the form on a page for a post, where replyable_type is Post and replyable_id is a post's ID, it works fine. When I submit a copy of the form on the same page, with the replyable_type set to Comment, and the replyable_id set to a comment's ID, the view the javascript does not run, at all. The action on the controller runs, using Firebug I can see the rendered javascript being sent back in response to the post request, and the comment is added to the database.
There are no errors in either the Rails console for generating the javascript or in the Firebug console to do with running the generated javascript. There are also no errors in the #comment.errors array. Even the first console.log in the Javascript is not run when the replyable object is a comment, despite being present in the rendered javascript.
What could cause this? I am using Rails 3.2.13 on Ruby 1.9.3

AJAX micropost's comments on the user page

On the user's page there are microposts and each of them have it's own comment form and comments. Using "Endless Page" railscast i'm trying to create "show more comments" button, which will load comments by AJAX. But it's not working.
The problem is in show.js.erb file because:
1) common pagination of comments (without AJAX) is working well
2) "show more button" is working well too. I tested it on the users list page
I think "show more comments" not working because it don'understand <%= j render(comments) %> , <%= j will_paginate(comments) %> and i should have here variables like <%= j render(#comments) %> , <%= j will_paginate(#comments) %>.
But when i try to write in my users_controller.rb
def show
#micropost = Micropost.find(params[:micropost_id])
#comments = #micropost.comments
end
it's not working because on my user's page there are many microposts and i have an error "Couldn't find micropost without an id". So in my microposts/_micropost.html.erb i had to use this
<% comments = micropost.comments.paginate(:per_page => 5, :page => params[:page]) %>
<%= render comments %>
Can anyone please help? How should i change my show.js.erb?
users/show.html.erb
<%= render #microposts %>
microposts/_micropost.html.erb
...
micropost's content
...
<%= render 'comments/form', micropost: micropost %>
<% comments = micropost.comments.paginate(:per_page => 5, :page => params[:page]) %>
<div class="commentaries">
<%= render comments %>
</div>
<div id="append_and_paginate">
<%= will_paginate comments, :class =>"pagination", :page_links => false %>
</div>
javascripts/users.js.coffee
jQuery ->
if $('.pagination').length
$('#append_and_paginate').prepend('<a id="append_more_results" href="javascript:void(0);">Show more</a>');
$('#append_more_results').click ->
url = $('.pagination .next_page').attr('href')
if url
$('.pagination').text('Fetching more...')
$.getScript(url)
users/show.js.erb
$('.commentaries').append('<%= j render(comments) %>');
<% if comments.next_page %>
$('.pagination').replaceWith('<%= j will_paginate(comments) %>');
<% else %>
$('.pagination').remove();
<% end %>
<% sleep 0.3 %>
Bennington, in users/show.html.erb you have
But #microposts is not defined in your controller. What I think you want is to define #microposts as all the microposts associated with what, a User?
If so, you'd want something like `#microposts = Micropost.where(:user_id => current_user.id) or something.

Categories

Resources