how to check available in client side with ajax, ruby on rails - ruby-on-rails

I'm new in ruby on rails, and i'm trying to check validate with ajax in client side(NOT CHECK AFTER POST), I have succeeded in checking not null, but i don't know to check available. I tried some codes but i have this error:
NameError in Welcome#index
../welcome/index.html.erb where line #17 raised:
undefined local variable or method `name' for #<#<Class:0x3d80e28>:0x3354b58>
Extracted source (around line #17):
14: } else if (phonenumber == "" && email == ""){
15: alert("Please enter your email or phonenumber in the form");
16: return false;
17: } else if (<% #usernames.include?("#{name}")%>){
18: alert("Please change your name");
19: }
20: });
Here is my ajax in html:
<script>
$(document).ready(function() {
$("#button").click(function() {
var email = $("#email").val();
var name = $("#username").val();
var phonenumber = $("#phonenumber").val();
var pass = $("#password").val();
if (name == "") {
alert("Please enter your Name in the form");
return false;
} else if (pass == "") {
alert("Please enter your Password in the form");
return false;
} else if (phonenumber == "" && email == ""){
alert("Please enter your email or phonenumber in the form");
return false;
} else if (<% #usernames.include?("#{name}")%>){
alert("Please change your name");
}
});
});
</script>
Because i want to check username in client side, so i must call '#usernames' in controller, here is my controller:
def index
#usernames = User.find(:all, :select => "username")
#user = User.create(:username => params[:username], :password => params[:password],
:email => params[:email], :phonenumber => params[:phonenumber])
if #user
render 'index'
else
render 'index'
end
end
I know my problem is I don't have 'name' method in controller, but i want to check "name" in client side. So please help me to fix that! Or help me to try another way to check available :)
Update:
I tried to create :
var names = <%= #usernames%>
but i have this error in log:
SyntaxError: illegal character

Are you trying to populate all the usernames in js? Really ? Don't do it, you're in a way exposing all the usernames to people while you are trying to validate it instantly.
For client side validation you could use jquery validation plugin which could be found here which separates validation from rest of your js code.
Also to validate if a username is available to be allotted to a user, you can fire ajax when user starts typing. Additionally you can rely on model errors for uniqueness.
In your model you could write validates :username, :uniqueness => true so you don't have to change your code and rails will give you appropriate error messages.
I hope that helps.

Related

How to pass value through link in controller function

How to pass value through link in controller function.
I want to pass below rc value in link so that routes collect it and send to controller.I am new bies in rails.Anyone please help me to solve the problem.
my html.erb .which collect value from text box through jQuery function.
<script type="text/javascript">
var rc=jQuery("#commonid").val();
</script>
<div ><%=link_to "Alert By Region",alerts/filter_alert %></div>
my routes.rb
file which match the link and send to controller
match 'alerts/filter_alert', :controller => 'alerts', :action => 'filter_alert'
my controller
def filter_alert(x)
#message=x
#title = #title + ' - Alerts'
render :site_alerts
end
Javascript things belong to Javascript. You need to manipulate this value dynamically upon visitor's clicking this link.
In Rails' controller side, you can't hard code the method. You need to use params from query string because you won't know what the input is.
# Views
link_to 'Alert By Region', 'alerts/filter_alert', id: 'alert-link'
# Javascript
$('#alert-link').on('click', function() {
var rc = $("#commonid").val();
if rc {
this.attr['href'] += '?rc='+ encodeURI(rc);
return true;
} else {
alert 'input is blank!';
return false;
}
});
# Controller
def filter_alert
rc = params[:rc]
# Then process based on this
end

Check if subject exist and append next to text box

I have a rails app that has a subject text field where the user input subject code id then beside the text field will the result of other details of the subjects when I blur the text field.
form:
SC_ID: <%= f.text_field "subject1", :id => "subject1"%>
jquery:
$('#subject1').blur(function() {
var field_value = $(this).val();
$.post("<%= validate_subject_path %>",{subject : field_value}, function(data) {
success: function() {
alert("Hahaha!");
},
error: function() {
alert("Subject not found!");
}
});
});
controller:
def validate_subject
sc_id = params[:subject].to_i
#subject = Subject.find_by_sc_id(sc_id)
string = "#{#subject.id}"
return string
render :layout => false
end
routes:
map.validate_subject '/subjects/validate_subject', :controller => "subjects", :action => 'validate_subject'
But when I try to blur no alert box is coming out.
Your $.post call is wrong, it should be something like this:
$.post("<%= validate_subject_path %>",{subject : field_value}, function(data) {
// not returning a hash
alert("Hahaha!");
});
If you really when to react on failures than you need to use $.ajax instead of $.post http://api.jquery.com/jQuery.ajax/

Rails is attempting to render remotely... but not

I'm working on a rails application and am attempting to convert the event_calendar gem's "next month" link into an ajax response.
I set the link to remote:
def month_link(month_date)
link_to I18n.localize(month_date, :format => "%B"),
{:month => month_date.month, :year => month_date.year},
remote: true
end
told it to respond to js...
respond_to do |format|
format.html
format.js { render text: "help me!" }
end
And it works!
Started GET "/calendar/2012/6" for 127.0.0.1 at 2012-07-03 15:27:42 -0500
Processing by CalendarController#index as JS
Parameters: {"year"=>"2012", "month"=>"6"}
Event Load (0.3ms) SELECT "events".* FROM "events" WHERE (('2012-05-27 05:00:00.000000' <= end_at) AND (start_at< '2012-07-01 05:00:00.000000')) ORDER BY start_at ASC
Rendered text template (0.0ms)
Completed 200 OK in 14ms (Views: 0.7ms | ActiveRecord: 0.3ms)
well... except for the part where it doesn't actually render anything I pass it. If I just tell it to format.js w/o the render, it doesn't actually respond to a js file.
What could cause a render to not display?
Updates
I just noticed that if you access the url like so localhost:3000/calendar/2012/6.js It works as expected, So I would assume it's an issue with how the link is set up?
Ok, I got the js file working, but I have no clue why. I think I was miss-using render (although I could have sworn I had used it for debugging purposes once). I guess render only actually render an html page when responding to an html request. Would make sense since it passes json to javascript for ajax requests.
Another part of the issue was I was trying to use CoffeeScript with either index.js.coffee.erb or index.js.erb.coffee. I thought it was working for the longest time, but what was really happening, was it was using the original index.js.erb I had written first, even though I had already deleted it. Once I restarted the server, everything broke.
Try this:
def month_link(month_date)
link_to I18n.localize(month_date, :format => "%B"),
{:remote=>true, :month => month_date.month, :year => month_date.year}
end
The format of link_to you are wanting to use is:
link_to(body, url_options = {}, html_options = {})
The :remote=>true wants to be in the url_options. I'm not sure what the :month & :year keys are for, but if they are html options, you would want this:
def month_link(month_date)
link_to I18n.localize(month_date, :format => "%B"),
{:remote=>true},
{:month => month_date.month, :year => month_date.year}
end
It seems that by default the remote option ignores any attempts to render or redirect. Considering that the point of Ajax is to prevent both of these... I can see why.
For self reference here is what (to my knowledge) happens when you create a remote link_to:
line 51 of jquery_ujs.js
$.rails = rails = {
// Link elements bound by jquery-ujs
linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote], a[data-disable-with]',
following linkClickSelector we find this function at line 300
$(document).delegate(rails.linkClickSelector, 'click.rails', function(e) {
var link = $(this), method = link.data('method'), data = link.data('params');
if (!rails.allowAction(link)) return rails.stopEverything(e);
if (link.is(rails.linkDisableSelector)) rails.disableElement(link);
if (link.data('remote') !== undefined) {
if ( (e.metaKey || e.ctrlKey) && (!method || method === 'GET') && !data ) { return true; }
if (rails.handleRemote(link) === false) { rails.enableElement(link); }
return false;
} else if (link.data('method')) {
rails.handleMethod(link);
return false;
}
});
Assuming that handleRemote handles the AJAX we wind up at line 107 to find this monster
// Submits "remote" forms and links with ajax
handleRemote: function(element) {
var method, url, data, crossDomain, dataType, options;
if (rails.fire(element, 'ajax:before')) {
crossDomain = element.data('cross-domain') || null;
dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType);
if (element.is('form')) {
method = element.attr('method');
url = element.attr('action');
data = element.serializeArray();
// memoized value from clicked submit button
var button = element.data('ujs:submit-button');
if (button) {
data.push(button);
element.data('ujs:submit-button', null);
}
} else if (element.is(rails.inputChangeSelector)) {
method = element.data('method');
url = element.data('url');
data = element.serialize();
if (element.data('params')) data = data + "&" + element.data('params');
} else {
method = element.data('method');
url = rails.href(element);
data = element.data('params') || null;
}
options = {
type: method || 'GET', data: data, dataType: dataType, crossDomain: crossDomain,
// stopping the "ajax:beforeSend" event will cancel the ajax request
beforeSend: function(xhr, settings) {
if (settings.dataType === undefined) {
xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
}
return rails.fire(element, 'ajax:beforeSend', [xhr, settings]);
},
success: function(data, status, xhr) {
element.trigger('ajax:success', [data, status, xhr]);
},
complete: function(xhr, status) {
element.trigger('ajax:complete', [xhr, status]);
},
error: function(xhr, status, error) {
element.trigger('ajax:error', [xhr, status, error]);
}
};
// Only pass url to `ajax` options if not blank
if (url) { options.url = url; }
return rails.ajax(options);
} else {
return false;
}
},

Really having difficulty with New tokens on token input (from different model)

Im using jquery-tokeninput, but a fork of it which allows the User to add new custom tokens (Tag) for each Resource.
Example here (Scroll down to the tag box and type a few letters. you can type ones that dont exist): http://www.tomsguide.fr/solutions/nouveau_sujet.htm
The current return value from the fork I'm using is this (new value in quotes):
16,42,'Subway',37,'McDonald\'s',734
I'm having extreme difficulty trying to handle this in Rails. This sums it up perfectly.
This is what I have so far, and its not working, probably for a lot of reasons I'm not seeing, but the main reason is that I need to create new Tag instances but not save them, that way I can somehow pass them back into the token input, and save the new Tags along with the new Resource when they submit the form. When you use Tag.new though, it doesnt create an ID.
resource.rb
attr_accessor :tokens_list
# CUSTOM TOKENS
def tag_tokens=(tokens)
self.tokens_list = tokens.split(",")
if new_custom_tokens?
self.tokens_list.each do |token|
tokens_list << token if token.include? "'"
end
end
self.tag_ids = self.tokens_list
end
def new_custom_tokens?
self.tokens_list.each do |token|
return true if token.include? "'"
end
false
end
resources_controller.rb
def create
#title = "Submit Resource"
#resource = Resource.new(params[:resource])
assign_to_global_user?
# CUSTOM TOKENS
if #resource.new_custom_tokens?
custom_token_time_restriction
# Create Tag.new
end
if #resource.valid?
#resource.save
flash[:notice] = "Your link has been successfully submitted."
redirect_to root_url
else
render :action => :new
end
end
def assign_to_global_user?
if user_signed_in?
#resource.user_id = current_user.id
else
#resource.user_id = User.find_by_username("Global_User").id
end
end
private
# CUSTOM TOKENS
def custom_token_time_restriction
limit = 7 # days
if (#resource.user_id != User.global_user_id) and (Time.now - limit.days > User.find(#resource.user_id).created_at)
# TODO: Check if they are anonymous or their account is newer than 7 days
else
flash[:notice] = "You be Logged in to add new tags, and your account must be older than #{limit} days."
render :action => :new
end
end
new.html.erb (for resource#new)
<div class="field">
<%= f.label :tags %>
<%= f.text_field :tag_tokens, "data-pre" => #resource.tags.to_json(:only => [:id, :name]), :class => :tagbox %>
</div>
I had the same problem. This is what I have done:
This is the function where I return tokens of search in json format.
tags = TagMaster.where("name LIKE ?", "%#{params[:q]}%").limit(10)
if tags == []
list << {"id" => "0","name"=>new_tag.rstrip}
else
tags.each { |tag| list << {"id" => tag.id.to_s, "name" => tag.name }}
end
respond_to do |format|
format.json { render :json => list.to_json, :layout => false }
end
Now this will allow show you whatever you type in auto complete dropdown and on clicked it will show as a token.
Now you can't add any more custom tokens because any token that is not in database will return id 0 so only one custom token is allowed at this point of time.
For that problem I did following.
var k = jQuery.noConflict();
k("#project_tags").tokenInput("tag_list", {
hintText: "Enter Tags for your Project",
noResultsText: "No Such Tags",
searchingText: "Looking for your Tags",
preventDuplicates: true,
theme: "facebook",
onAdd: function (item) {
if (item.id == '0') {
k.ajax({
url: '/add_project_tag',
data: { name: item.name },
success:function(data) {
k("#project_tags").tokenInput("add", {id: data, name: item.name});
k("#project_tags").tokenInput("remove", {id: '0' });
}
});
}
}
});
As you can see here i call add_project_tag where I store that custom tag into database and it returns id of that inserted tag. So now you simply add the same token with it's id and remove token with 0.
So now there won't be any token with 0 and you can add as many new token as you want.
Hope this helps. Throw your questions if any more complications.

Check username availability

I have a form to user login:
<%= form_tag(#action, :method => "post", :name => 'signup' ,:onSubmit => 'return validate();') do %>
<%= label_tag(:user, "Username:") %>
<%= text_field_tag(:user) %>
I want to check if there is the username in the database immediately after :user-field lost focus. I can override this event on the form with javascript, but I can not send Ruby-AJAX request from javascipt code.
Is there any way to check username without adding additional controls (buttons, links) on the form?
You can use some JavaScript (this one written with jQuery) for AJAX cheking:
$(function() {
$('[data-validate]').blur(function() {
$this = $(this);
$.get($this.data('validate'), {
user: $this.val()
}).success(function() {
$this.removeClass('field_with_errors');
}).error(function() {
$this.addClass('field_with_errors');
});
});
});
This JavaScript will look for any fields with attribute data-validate. Then it assings onBlur event handler (focus lost in JavaScript world). On blur handler will send AJAX request to the URL specified in data-validate attribute and pass parameter user with input value.
Next modify your view to add attribute data-validate with validation URL:
<%= text_field_tag(:user, :'data-validate' => '/users/checkname') %>
Next add route:
resources :users do
collection do
get 'checkname'
end
end
And last step create your validation:
class UsersController < ApplicationController
def checkname
if User.where('user = ?', params[:user]).count == 0
render :nothing => true, :status => 200
else
render :nothing => true, :status => 409
end
return
end
#... other controller stuff
end
For what reason can you not send an ajax request from javascript code?
The best way would be to send a GET ajax request when the focus is lost. The get request could then return true or false and your javascript could then reflect this on the page.
I answered this in another post.
It is a friendly way for validating forms if you do not want to write it all from scratch using an existing jquery plugin. Check it out and if you like it let me know!
Check username availability using jquery and Ajax in rails
The solution that #Viacheslav has, works fine and my answer is a combination of his and my own changes (especially JS) part.
We will be using Ajax in order to achieve this.
Lets first create our function in the controller
def checkname
if !User.find_by_display_name(params[:dn])
render json: {status: 200}
else
render json: {status: 409}
end
return
end
and then adding our routes in routes.rb
resources :yourcontroller do
collection do
get 'checkname'
end
end
Now lets gets our hand on the view. Below you'll see the input:
.field
= f.text_field :display_name, onblur: "checkDisplayName.validate(this.value)"
%p.error-name.disp-none username exists
And now by help of JSwe get the magic rolling. Blow JS has few functions. validate does the actually validation. getStatus is our Ajax call to get the status and we use showError & disableSubmitButton to our form a bit more production ready to show errors and disabling the submit button.
var checkDisplayName = {
validate: function(dn){
checkDisplayName.getStatus(dn).then(function(result) {
if (!!result){
if (result.status != 200){
checkDisplayName.disableSubmitButton(true);
checkDisplayName.showError();
} else{
checkDisplayName.disableSubmitButton(false);
}
}
});
return false;
},
getStatus: async (dn) => {
const data = await fetch("/pages/checkname?dn=" + dn)
.then(response => response.json())
.then(json => {
return json;
})
.catch(e => {
return false
});
return data;
},
showError: function() {
let errEl = document.getElementsByClassName('error-name')[0];
if (!!errEl) {
errEl.classList.remove("disp-none");
window.setTimeout(function() { errEl.classList.add("disp-none"); },3500);
}
},
disableSubmitButton: function(status){
let button = document.querySelector('[type="submit"]');
button.disabled = status;
}
};

Resources