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

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.

Related

Create multiple objects on a button click in Rails

I have template_sections and sections and on a button click in my view I want
a) get all template_sections with a specific template_id, send them to the sections_controller
or
b) the section_controller method transform should get the template_sections there
and
iterate over them and create a new section object for each one of them, where I would set is_template = 0 and template_id = nil and save them.
View:
<div class="col-2 deploy-template">
<%= button_to 'Deploy Template', transform_sections_path, method: :post, *{call controller's method or send objects from here to transform method}*, remote: true, type: 'button', class: "btn btn-secondary btn-sm ml-0 mr-4" %>
</div>
Controller:
def new
#section = Section.new
if params[:is_template]
date = (Time.at(params['day'].to_i*86400-1)).strftime("%Y-%m-%d")
#section.starts_at_datetime = (date + ' ' + params['time']).in_time_zone rescue nil
else
#section.starts_at_datetime = (params['date'] + ' ' + params['time']).in_time_zone rescue nil
end
respond_to do |format|
format.js
end
end
def create
#section = Section.new(section_params)
#section.account_id = session_account_id
#section.is_template = true if params[:section][:is_template] == 'true'
#section.template_id = params[:section][:template_id]
respond_to do |format|
if #section.save
format.js
flash.now[:success] = "saved successfuly"
create_event #section, "create", "Create"
else
flash.now[:danger] = "#{#section.errors.full_messages}"
format.js { render 'layouts/notifications' }
end
end
end
def transform
template_sections.each do |template_section|
#save each template_section with is_template = 0 and template_id = nil
end
What you can do is pass your template sections to your controller through the params hash like so:
<%= button_to 'Deploy Template', method: :post, transform_sections_path(template_sections: [YOUR ARRAY VARIABLE HERE]), remote: true, type: 'button', class: "btn btn-secondary btn-sm ml-0 mr-4" %>
Your template sections should then be available through params[:template_sections] inside of your controller for you to do whatever you feel like doing, (I am assuming post: template_sections_path points to the transform action in your controller).
def transform
template_sections = params[:template_sections]
template_sections.each do |template_section|
#save each template_section with is_template = 0 and template_id = nil
end
I don't know what your TemplateSection model looks like so I will refrain from writing controller code that won't work, but hopefully once you have the data in your controller you will be able to work through it, and if not I am happy to help with a little bit more information.
As an additional note, "method: :post", and "type: button" seem redundant when using a button_to tag as those are the defaults, you can remove them unless you have a specific reason for having them.

Rails select2 after create new tag i haven't id on create action

I use select2 and want to create new tags and then save them.
i have form for #cost and for select2 this
<%= f.collection_select :product_ids, Product.all,:id, :name ,{include_hidden: false},{ multiple: true} %>
for creation new product i have this js code
$(document).ready(function () {
$('#cost_product_ids').select2({
tags: true,
tokenSeparators: [",", " "],
createProduct: function (product) {
return {
id: product.term,
text: product.term,
isNew: true
};
}
}).on("change", function (e) {
var isNew = $(this).find('[data-select2-tag="true"]');
if (isNew.length) {
$.ajax({
type: "POST",
url: "/product_new",
data: {product: isNew.val()}
});
}
});
});
and controller method for save new product
def product_new
product = Product.find_by(name:params[:product])
Product.create(name:params[:product]) if !product
render json: :ok
end
cost create action
def create
#cost = Cost.new(costs_params)
if #cost.save
flash[:notice] = t('added')
if params[:add_more].present?
redirect_back(fallback_location: root_path)
else
redirect_to #cost
end
else
render action: 'edit'
end
end
def costs_params
params.require(:cost).permit(:day, :amount, :description, :source,:tag_list,:product_ids=>[])
end
it works ok, but when i want to save my #cost record with this newly created product i have received only name of my tag without id.
For example i have products water=>id:1,beer=>id:2,and create new juice tag in db it has id:3
on create in have params "product_ids"=>["1", "2", "juice"]
How to fix it?
you shouldn't use id: product.term,
but id: product.id,

Implementing ajax request to create/edit rails object

I am trying to create a add/edit credit card form within my edit user page. To do so I am trying to implement an ajax call to the edit and create functions in my customers controller.
This is the code I have for the update button within the modal window:
<%= button_tag "Update", :class =>"btn submit-button", :type => 'button', :onclick => "onUpdateCard('#{current_user.id}');"%>
This is the function that it calls:
function onUpdateCard(id) {
this.id = id;
// disable the submit button to prevent repeated clicks
$('.submit-button').attr("disabled", "disabled");
var card_number = document.getElementById('card_number').value;
var card_code = document.getElementById('card_code').value;
var card_month = document.getElementById('card_month').value;
var card_year = document.getElementById('card_year').value;
var response = Stripe.createToken({
number: $('#card_number').val(),
cvc: $('#card_code').val(),
exp_month: $('#card_month').val(),
exp_year: $('#card_year').val()
}, stripeResponseHandler);
// allow the form to submit with the default action
return false;
};
function stripeResponseHandler(status, response) {
if (response.error) {
$(".payment-errors").text(response.error.message);
$(".submit-button").removeAttr("disabled");
} else {
var token = response['id'];
var new_url = "/users/" + this.id + "/customers/new";
var edit_url = "/users/" + this.id + "/customers/1/edit";
$.ajax({
type:'GET',
url: edit_url,
data: {'stripe_card_token': token}
});
}
return false;
};
And in the controller there is the edit function:
def edit
#user = current_user
#customer = #user.customer
stripe_customer = Stripe::Customer.retrieve(#customer.stripe_customer_token)
stripe_customer.card = params[:stripe_card_token]
stripe_customer.save
end
Can you help me figure out how to handle the ajax correctly? I'm not sure how to debug this properly...
Here I'm suggesting the alternative to handle update request using AJAX.
I'm not improving or correcting your code but giving you a way to handle AJAX requests in Rails 3.
a. view
Whatever information you wants to update in Database using AJAX call you will pass through a form. So for making a AJAX request you need to add :remote => true in your form. Rails provides this helper.
<%= form_for #customer, :url => admin_customers_path, :method => :post, :remote => true, :html => { :id => "customer-form" } do |form|-%>
<%= render :partial => 'admin/customers/form', :object => form %>
<%= form.submit 'Update' %>
<% end %>
In the _form.html.erb you can add textfield or other this whatever you wants to add in your edit form
b. controller
Because of " :remote => true " you form submission will make a JS request so in update action after saving the data of customer
control will for to format.js and then it will look for update.js.erb in views.
def update
if #customer.update_attributes(params[:customer])
respond_to do |format|
format.html {
flash[:success] = "customer's info was updated Successfully."
redirect_to customers_path
}
format.js
end
else
respond_to do |format|
format.html {
flash[:error] = #customer.errors.present? ? #customer.errors.full_messages.join('<br />') : "Oops! There is some problem with category update."
render :edit
}
format.js
end
end
end
c. update.js.erb
You can do stuffs after successful update. Suppose you want to highlight some div then you can do like this.
$('.target-div').effect("highlight", {}, 2500);

Push name to results unless the name already exists?

I have the following in my tags controller (params[:q] comes from this plugin: http://loopj.com/jquery-tokeninput/). This is basically a slightly modified product of this screencast: http://railscasts.com/episodes/258-token-fields.
tags_controller.rb:
class TagsController < ApplicationController
def index
#tags = Tag.where("name like ?", "%#{params[:q]}%")
results = #tags.map(&:attributes)
results << {:name => "Add: #{params[:q]}", :id => "CREATE_#{params[:q]}_END"}
respond_to do |format|
format.html
format.json { render :json => results }
end
end
I want to only do results << {:name => "Add: #{params[:q]}", :id => "CREATE_#{params[:q]}_END"} only if the name doesn't exist already in #tags. Because right now, it looks like this:
programming #input field
programming #drop-down menu
Add: progamming #drop-down menu
I want it to just display like
programming #input field
Add: progamming #drop-down menu
How to accomplish that?
EDIT:
Here is the model and JavaScript just in case:
application.js
$(function() {
$("#post_tag_tokens").tokenInput("/tags.json", {
crossDomain: false,
prePopulate: $("#post_tag_tokens").data("pre"),
preventDuplicates: true,
theme: "facebook"
});
});
post.rb:
def tag_tokens=(ids)
ids.gsub!(/CREATE_(.+?)_END/) do
Tag.find_or_create_by_name(:name => $1).id
end
self.tag_ids = ids.split(",")
end
You can do this:
#tag = Tag.find_by_name(params[:q])
or
#tag = Tag.name_like(params[:q]) #For this you need to install gem [searchlogic][1]
if #tag.blank?
# Do you things
end

How I can dynamically generate url ( for generating xls report )?

Hello!
I have this trouble: I'm searching reports by date and in html view everything is alright, BUT when I'm rendering xls view error appear, because it didn't receive params, so I need to pass them in URL for xls link_to generator.
My controller:
def show
#website = Website.find(params[:id])
if params[:report] && params[:report][:start_date] && params[:report][:end_date]
#search_by_created_at
#performance_reports = #website.performance_reports.where("created_at between ? and ?", params[:report][:start_date].to_date, params[:report][:end_date].to_date)
else
#performance_reports = #website.performance_reports
end
respond_to do |format|
format.html # index.html.erb
format.xls
format.xml { render :xml => #performance_reports }
end
end
and my generated url looks like:
http://127.0.0.1:3000/websites/25/performance_reports/show?utf8=%E2%9C%93&report[end_date]=07%2F09%2F2012&report[start_date]=04%2F09%2F2012&commit=Run+Report
mine xls url is generated like this:
<%= link_to url_for(:format => 'xls') do%>
<%= image_tag("excel.png", :id => "analytics",:size => '21x23')%> <b>Export</b>
<% end %>
result:
http://127.0.0.1:3000/websites/25/performance_reports/show
Any help will be appreciated.
xls in not available by default.
Add this:
gem "spreadsheet"
gem "to_xls", :git => "https://github.com/dblock/to_xls.git", :branch => "to-xls-on-models"
Register the Excel MIME type in config/initializers/mime_types.rb by adding this:
Mime::Type.register "application/vnd.ms-excel", :xls
Add an as_xls method to model that you want to export for the fields you want.
For example for a User model you might have:
def as_xls(options = {})
{
"Id" => id.to_s,
"Name" => name,
"E-Mail" => email,
"Joined" => created_at,
"Last Signed In" => last_sign_in_at,
"Sign In Count" => sign_in_count
}
end
Add code to the controller:
def index
#users = User.all
respond_to do |format|
format.html
format.xls { send_data #users.to_xls, content_type: 'application/vnd.ms-excel', filename: 'users.xls' }
end
end
Provide a link:
= link_to 'Export', users_path(request.parameters.merge({:format => :xls}))
All code should have a test. You could do something like this:
describe "GET index.xls" do
it "creates an Excel spreadsheet with all users" do
user = Fabricate :user
get :index, :format => :xls
response.headers['Content-Type'].should == "application/vnd.ms-excel"
s = Spreadsheet.open(StringIO.new(response.body))
s.worksheets.count.should == 1
w = s.worksheet(0)
w.should_not be_nil
w.row(0)[0].should == "Id"
w.row(1)[0].should == user.id.to_s
w.row(0)[1].should == "Name"
w.row(1)[1].should == user.name
end
end

Resources