Rails. SmartListing gem doesn't refresh table after destroying item - ruby-on-rails

I have page with table of categories. I'm using SmartListing GEM for sorting data and also I added some buttons for each item in table, including "delete" button.
Problem: after element in the table was deleted, table blinks but doesn't refresh data, so I need to reload hole page to get updated table. (By the way, element removed from the database without problems)
My files look like the files in developer example.
My files:
index and destroy actions in CategoriesController
def index
#categories = Category.all
smart_listing_create :categories, #categories,
sort_attributes: [
[:created_at, 'categories.created_at'],
[:updated_at, 'categories.updated_at'],
[:name, 'categories.name'],
[:calculate, 'categories.issues_count']
],
default_sort: { name: 'asc' }, partial: 'category'
end
def destroy
#category = Category.find(params[:id])
if #category.issues.empty?
#category.destroy
flash[:success] = 'Deleted'
else
flash[:alert] = 'Category isn\'t empty!'
end
end
index.html.slim
#heading-breadcrumbs
.container
.row
.col-md-7
h1=title 'Categories'
.col-md-5
ul.breadcrumb
li= link_to 'Main', root_path
li Categories
#content
.container
.row
#categories-moderation.col-md-12.col-sm-12.col-xs-12
= link_to 'Create new', new_account_admin_category_path, class: "newcategory btn btn-lg btn-info"
= smart_listing_render(:categories)
_category.html.slim
- unless smart_listing.empty?
.table-responsive
table.table.table-hover.flex-table
thead
tr.centered
th.col-md-2.col-sm-3
= smart_listing.sortable 'Created', :created_at
th.col-md-2.col-sm-3
= smart_listing.sortable 'Updated', :updated_at
th.col-md-4.col-sm-3
= smart_listing.sortable 'Title', :name
th.col-md-2.col-sm-2.hidden-title
= smart_listing.sortable 'Issues', :calculate
th.col-md-2.col-sm-2.hidden-title
| Actions
tbody
- smart_listing.collection.each do |category|
tr.editable[data-id=category.id]
= smart_listing.render object: category, partial: 'category_item', locals: {object: category}
= smart_listing.paginate
- else
p Empty
_category_item.html.slim
tr.centered
td.col-md-2.col-sm-3.col-xs-12.flex-order-0
span.user-label Created:
= object.created_at.strftime("%m.%d.%Y, %T")
td.td.col-md-2.col-sm-3.col-xs-12.flex-order-1
span.user-label Updated:
= object.updated_at.strftime("%m.%d.%Y, %T")
td.lefted.col-md-4.col-sm-2.col-xs-12.flex-order-2
= link_to object.name, object
td.issues_count.col-md-2.col-sm-5.col-xs-12.flex-order-3
span.user-label Issues:
= render partial: 'shared/number_of_issues', locals: { id: object.id }
td.actions.col-md-4.col-sm-5.col-xs-12.flex-order-4
= smart_listing_item_actions [{name: :edit,
url: edit_account_admin_category_path(object),
icon: 'glyphicon glyphicon-pencil',
title: 'Edit'},
{name: :destroy,
url: account_admin_category_path(object),
confirmation: 'Sure?',
icon: 'glyphicon glyphicon-trash',
remote: true, if: object.issue_ids.empty?,
title: 'Delete'}]
index.js.erb
<%= smart_listing_update(:categories) %>
update.js.erb
<%= smart_listing_item :categories, :update, #category, 'category_item' %>
destroy.js.erb
<%= smart_listing_item :categories, :destroy, #category %>
Problem: after element in the table was deleted, table blinks but doesn't refresh data, so I need to reload hole page to get updated table. (By the way, element removed from the database without problems)

I found a solution to the problem. It was resolved simply - just had to add to the destroy action line redirect_to action: 'index', status: 303, so this action should look like this:
def destroy
#category = Category.find(params[:id])
if #category.issues.empty?
#category.destroy
flash[:success] = 'Deleted'
redirect_to action: 'index', status: 303
else
flash[:alert] = 'Category isn\'t empty!'
end
end

Related

Auto-complete suggestion within a simple_form

I am building an application where i try to suggest "Similar topics" in rails, as the user put the title of his/her new story.
I have 2 problems:
The controller with the custom action does not work at all. it seems that the server simply retrieves the view. Without running any of the code in the action
To go around the issue of the controller, i created a service.rb with a function to retrieve the records based on the params[:title], but from here I do NOT know how to make small popup window with suggestions (and weblinks) as the user write the title of the topic.
I have done so far :
View
<div class="col-md-12">
<%= simple_form_for #message do |f| %>
<div style="font-size: xx-small; font-style: italic; color: #44B5EB">
<%= f.input :title, label: "#{t :Title}", placeholder: "#{t :Search}", id: "title" , data: {behavior: "autocomplete_message"}%>
<%= f.cktext_area :description, label: "#{t :Message_body}", :input_html => {:rows => 25} %>
<br> <br>
<%= f.submit "#{t :Create_story}", class: "btn btn-primary"%>
<% end %>
</div>
</div>
<script>
$("#title").addEventListener("turbolinks:load", function () {
$input = $("[data-behavior = 'autocomplete_message']");
var options = {
getValue: "name",
url: function (phrase) {
return "messages/search.json?title=" + phrase;
},
categories: [
{
listLocation: "qandas",
header: "<p class='Search_drop_separate'>Q&A </p>",
}
],
list: {
onChooseEvent: function(){
var url = $input.getSelectedItemData().url;
$input.val("");
Turbolinks.visit(url)
}
}
};
$input.easyAutocomplete(options)
});
</script>
Controller
class StorytController < ApplicationController
before_action :authenticate_user!
before_action :find_message, only: [:show, :edit, :update, :destroy]
respond_to :html, :js
...
def search
##qandasquestions = Qandasquestion.ransack(question_or_answer_cont: params[:q]).result(distinct: true)
respond_to do |format|
format.html {
#qandasquestions = #qandasquestions
redirect_to stories_search_path
}
format.json {
#qandasquestions = #qandasquestions.limit(5)
}
end
end
def full_name
"#{first_name} #{last_name}"
end
private
def force_json
request.format = :json
end
end
Search.jason.builder
json.qandas do
json.array!(#qandasquestions) do |qandasquestion|
json.name "#{qandasquestion.question}"
json.url qanda_path(qandasquestion.qanda_id)
end
end
routes:
get 'stories/search'
What I am looking to build is actually very similar to what we have on Stackoverflow on the principle.
Anybody did something similar and can help me please?
I don't mean to sidetrack you but if you have a couple minutes to check this out, have you seen select2? It works nice with Rails and there's also a gem to make it work nice with simple_form
https://github.com/lndl/select2_simple_form

How to fix 'Rails.ajax' error in site Console?

I have 2 different post types (news and articles). When i go to news and try to comment any news, nothing happen. In google chrome console it says:
POST /news/artifact-v-spiske-liderov-prodazh-steam-po-itogam-2018-goda/comments/ 404
rails-ujs.self-d109d8c5c0194c8ad60b8838b2661c5596b5c955987f7cd4045eb2fb90ca5343.js?body=1:7
Rails.ajax # rails-ujs.self-d109d8c5c0194c8ad60b8838b2661c5596b5c955987f7cd4045eb2fb90ca5343.js?body=1:7
Rails.handleRemote # rails-ujs.self-d109d8c5c0194c8ad60b8838b2661c5596b5c955987f7cd4045eb2fb90ca5343.js?body=1:31
(anonymous) # rails-ujs.self-d109d8c5c0194c8ad60b8838b2661c5596b5c955987f7cd4045eb2fb90ca5343.js?body=1:5
BUT! When i try comment in Articles type, all good, comments work. What is problem?
My _form.html.haml:
- if user_signed_in? && current_user.mute_to && current_user.mute_to > Time.current
%div
%strong
= "Вы не можете писать комментарии до #{current_user.mute_to.strftime("%F %R")}"
- elsif user_signed_in?
= form_with model: [commentable, Comment.new], html: { class:
local_assigns[:class], data: { target: local_assigns[:target] } } do |form|
.form-group
= form.text_area :body, placeholder: "Напишите комментарий (минимум 3 символа)", class: "form-control"
.form-group
= form.hidden_field :parent_id, value: local_assigns[:parent_id]
= form.submit 'Отправить', class: "btn"
My _comment.html.haml:
- nesting = local_assigns.fetch(:nesting, 1)
- max_nesting = local_assigns[:max_nesting]
- continue_thread = local_assigns[:continue_thread]
= tag.div id: dom_id(comment), class: "border-left pl-4 my-4" do
- if comment.deleted?
%strong [комментарий удален]
%small
= link_to time_ago_in_words(comment.created_at), url_for(comment: comment.id, anchor: dom_id(comment))
%p [комментарий удален]
- else
- comments_user = comment.user
%strong.comments_user_line
= fa_icon "user-circle", class: "mr-1"
= link_to comments_user.nickname, user_path(comments_user), class: 'user_link'
%small
= link_to time_ago_in_words(comment.created_at), polymorphic_path(comment.commentable, comment: comment.id, anchor: dom_id(comment))
= simple_format comment.body
%div.comments_block
- if user_signed_in? && current_user.mute_to && current_user.mute_to > Time.current
- else
%small
- if user_signed_in?
%btn.reply Отвеить
- else
= link_to "Отвеить", new_user_session_path
= link_to "Удалить", [comment.commentable, comment], method: :delete, data: {confirm: "Вы уверены?"} if comment.user == current_user
= render partial: "comments/form", locals: { |
commentable: comment.commentable, |
parent_id: reply_to_comment_id(comment, nesting, max_nesting), |
class: "mt-4 d-none replies_form", |
target: "reply.form" |
} |
= tag.div id: "#{dom_id(comment)}_comments" do
- if continue_thread.present? && nesting >= continue_thread && comment.comments.any?
= link_to "Открыть ветку", url_for(comment: comment.id, anchor: dom_id(comment))
- else
= render comment.comments, continue_thread: continue_thread, nesting: nesting + 1, max_nesting: local_assigns[:max_nesting]
My comments_controller.rb:
class CommentsController < ApplicationController
before_action :authenticate_user!
def create
#comment = #commentable.comments.new(comment_params)
#comment.user = current_user
if #comment.save
respond_to do |format|
format.html { redirect_to #commentable }
format.js
end
else
redirect_to #commentable, alert: "Ошибка :("
end
end
def destroy
#comment = #commentable.comments.find(params[:id])
return false unless current_user.id == #comment.user_id
#comment.destroy
redirect_to #commentable
end
private
def comment_params
params.require(:comment).permit(:body, :parent_id)
end
end
If i uncomment rails-ujs in application.js like this:
require rails-ujs
Then when i posting comment it will be say:
ActiveRecord::RecordNotFound in News::CommentsController#create
Couldn't find News with 'id'=artifact-v-spiske-liderov-prodazh-steam-po-itogam-2018-goda
Extracted source (around line #7):
6 def set_commentable
7 #commentable = News.find(params[:news_id])
8 end
9 end
How i can fix it? Thanks!
The first suggestion - comment require rails-ujs until you solve the issue. It will be easier to debug.
Then, the issue is that as a params[:news_id] you are passing news slug (artifact-v-spiske-liderov-prodazh-steam-po-itogam-2018-goda) instead of news id. One solution is to modify the code to pass news id as params[:news_id].
Another, a little big uglier solution, is to refactor set_commentable method in the News::CommentsController to something like this:
def set_commentable
#commentable = News.find_by(slug: params[:news_id])
end
However, it might break other places where set_commentable is used.

NoMethodError undefined method `id' for nil:NilClass:

I know this kind of question is already answered multiple times but i seriously unable to figure it out what is causing a problem here, I am having trouble solving this problem. I keep getting the same error when i'm trying to create new registration ( http://localhost:3000/registrations/new?course_id=1 ) :
NoMethodError at /registrations
undefined method `id' for nil:NilClass
Here is my RegistrationsController:
class RegistrationsController < ApplicationController
before_action :set_registration, only: [:show, :edit, :update, :destroy]
def index
#registrations = Registration.all
end
def show
end
def new
#registration = Registration.new
#course = Course.new
#course = Course.find_by id: params["course_id"]
end
def create
#registration = Registration.new registration_params.merge(email: stripe_params["stripeEmail"], card_token: stripe_params["stripeToken"])
raise "Please Check Registration Errors" unless #registration.valid?
#registration.process_payment
#registration.save
redirect_to #registration, notice: 'Registration was successfully created.'
rescue Exception => e
flash[:error] = e.message
render :new
end
protect_from_forgery except: :webhook
def webhook
event = Stripe::Event.retrieve(params["id"])
case event.type
when "invoice.payment_succeeded" #renew subscription
Registration.find_by_customer_id(event.data.object.customer).renew
end
render status: :ok, json: "success"
end
private
def stripe_params
params.permit :stripeEmail, :stripeToken
end
def set_registration
#registration = Registration.find(params[:id])
end
def registration_params
params.require(:registration).permit(:course_id, :full_name, :company, :telephone, :email, :card_token)
end
end
My Registration Model:
class Registration < ActiveRecord::Base
belongs_to :course
def process_payment
customer_data = {email: email, card: card_token}.merge((course.plan.blank?)? {}: {plan: course.plan})
customer = Stripe::Customer.create customer_data
Stripe::Charge.create customer: customer.id,
amount: course.price * 100,
description: course.name,
currency: 'usd'
#Annotate Customer Id when Registration is Created
cusotmer_id = customer.id
end
def renew
update_attibute :end_date, Date.today + 1.month
end
end
Registration New.html.haml File :
%section#course-content
%section#ruby
%section.detailed-syllabus
.wrapper-inside
= form_for #registration, html: { class: "basic-grey" } do |f|
- if #registration.errors.any?
#error_explanation
%h2
= pluralize(#registration.errors.count, "error")
prohibited this registration from being saved:
%ul
- #registration.errors.full_messages.each do |message|
%li= message
.field
= f.hidden_field :course_id, value: #course.id
.field
= f.label :full_name
= f.text_field :full_name
.field
= f.label :company
= f.text_field :company
.field
= f.label :email
= f.text_field :email
.field
= f.label :telephone
= f.text_field :telephone
//‘Stripe.js’ will recognize the card data because we have marked the inputs with ‘data-stripe’ attribute as: number, cvv, exp-month and exp-year.
= javascript_include_tag "https://js.stripe.com/v2/"
:javascript
Stripe.setPublishableKey('#{Rails.application.secrets.stripe_publishable_key}');
= label_tag "Card Number", nil, required: true
.control-group
.controls
= text_field_tag :card_number, nil, class: "input-block-level", "data-stripe" => "number"
= label_tag "Card Verification", nil, required: true
.control-group
.controls
= text_field_tag :card_verification, nil, class: "input-block-level", "data-stripe" => "cvv"
= label_tag "Card Expires", nil, required: true
= select_tag :exp_month, options_for_select(Date::MONTHNAMES.compact.each_with_index.map { |name,i| ["#{i+1} - #{name}", i+1] }), include_blank: false, "data-stripe" => "exp-month", class: "span2"
= select_tag :exp_year, options_for_select((Date.today.year..(Date.today.year+10)).to_a), include_blank: false, "data-stripe" => "exp-year", class: "span1"
.actions
= f.submit "Registration Payment", class: "btn", style: "color: white;background: rgb(242, 118, 73);"
Does anyone know how to assist me in this? Greatly appreciate all the help.
Additional Can anyone please guide me through how to pass id between 2 models like this guy did between 2 models as he's creating a scaffold for one model but passing ID lets him create values for another model too without creating actions for another controller https://github.com/gotealeaf/stripe-basics.git
Edited:
GitHub Repository For This Code
https://github.com/ChiragArya/Stripe_CheckOut_Demo
From your comments, it appears the error is caused by :
#course.id being nil
The way to fix this is to ensure #course is defined properly. You need to do the following:
def new
#registration = Registration.new
#course = Course.find_by id: params["course_id"]
end
The other issue you have here is that your routes should be able to handle courses without having to append them with ?course_id=1:
#config/routes.rb
resources :registrations do
get :course_id, to: "registrations#new" #-> yoururl.com/registrations/:course_id
end
This will still give you the course_id param in the new action; just makes it more Rails.
--
Controller
You also need some structure in your code (you're aiming for fat model, thin controller). It looks like you're coming to Rails as a Ruby dev; you need to appreciate that Rails handles most of the exceptions etc for you.
Specifically, you need to look at how to remove code out of your actions:
def create
#registration = Registration.new registration_params
#registration.process_payment
if #registration.save
redirect_to #registration, notice: 'Registration was successfully created.'
else
# handle error here
end
end
private
def registration_params
params.require(:registration).permit(:course_id, :full_name, :company, :telephone, :email, :card_token).merge(email: stripe_params["stripeEmail"], card_token: stripe_params["stripeToken"])
end
-
`id' for nil:NilClass
Finally, you have to remember this error basically means the variable you're trying to invoke an action for is nil.
Ruby populates nil variables with a NilClass object, thus it's difficult to determine what the error actually is. All it means is that the variable you're trying to call a method on doesn't have the aforementioned method, as Ruby has populated it with the NilClass object.
Try changing Registration#new action to
def new
#course = Course.find(params[:course_id])
#registration = #course.registrations.new
end
add this in your def create
def create
#course = Course.find_by id: params["registration"]["course_id"]
#registration = Registration.new registration_params.merge(email: stripe_params["stripeEmail"], card_token: stripe_params["stripeToken"])
raise "Please Check Registration Errors" unless #registration.valid?
#registration.process_payment
#registration.save
redirect_to #registration, notice: 'Registration was successfully created.'
rescue Exception => e
flash[:error] = e.message
#course = Course.find_by id: params["registration"]["course_id"]
render :new
end

Using AJAX with two select boxes in Rails 4

I have a view containing two select boxes: company and employee. Both have a blank option and when a company is selected, it populates the employees based on the selected company. This works just fine. My issue is that when I submit a form that fails validation (as expected) and I select a company once more once the 'new' view renders again in extensions#create, my 'get' AJAX call has changed from /servers/1/extensions/get_company_employees (correct) to /servers/1/get_company_employees (incorrect) and is returning 404 Not found. Why is this happening and what should I do to remedy this? All relevant code is listed below
routes.config
resources :servers do
scope module: 'servers' do
resources :extensions, shallow: true
end
end
# Ajax call
get 'servers/:id/extensions/get_company_employees', to: 'servers/extensions#get_company_employees', as: 'get_company_employees'
app/controllers/servers/extensions_controller.rb
class Servers::ExtensionsController < ApplicationController
def get_company_employees
#server = Server.find(params[:id])
#extension = #server.extensions.build
#path = [#server, #extension]
#companies = Company.all
#employees = Employee.where("company_id = ?", params[:company_id])
respond_to do |format|
format.js
end
end
def new
#server = Server.find(params[:server_id])
#extension = #server.extensions.build
#path = [#server, #extension]
#companies = Company.all
#employees = Employee.none
end
def create
#server = Server.find(params[:server_id])
#extension = #server.extensions.build(extension_params)
#extension.password = "pass"
if #extension.save
flash[:success] = "Successfully created extension"
redirect_to #extension
else
#path = [#server, #extension]
#companies = Company.all
#employees = Employee.none
flash.now[:error] = "Failed to create extension"
render "new"
end
end
private
def extension_params
params.require(:extension).permit(:value, :password, :employee_id, :server_id, :phone_id)
end
end
app/views/servers/extensions/_form.html.erb
<%= form_for(#path) do |f| %>
<p>
<%= label_tag(:company) %>
<%= select_tag "company", options_from_collection_for_select(#companies, "id", "name"), include_blank: "Select a company" %>
</p>
<p>
<%= f.label(:employee) %>
<%= f.collection_select :employee_id, #employees, :id, :full_name, include_blank: "Select an employee" %>
</p>
<p>
<%= f.submit "Submit" %>
</p>
<% end %>
app/views/servers/extensions/get_company_employees.js.coffee
$("#extension_employee_id").empty()
.append("<option>Select an employee</option>")
.append("<%= j options_from_collection_for_select(#employees, :id, :full_name) %>")
app/assets/javascripts/servers/extensions.coffee
$ ->
$(document).on 'page:load', '#company', (evt) ->
$.ajax 'get_company_employees',
type: 'GET'
dataType: 'script'
data: {
company_id: $("#company option:selected").val()
}
$(document).on 'change', '#company', (evt) ->
$.ajax 'get_company_employees',
type: 'GET'
dataType: 'script'
data: {
company_id: $("#company option:selected").val()
}
Its because you have now specified complete URL in ajax call
It should be something like this in both cases.
$.ajax "/servers/"+ id +"/extensions/get_company_employees',
type: 'GET'
dataType: 'script'
data: {
company_id: $("#company option:selected").val()
}
// store and fetch id attribute from page in any of the dom element
Ideally you should write a function for your ajax call which can be called wherever required and code redundancy can be reduced.

Filtering values of index page on values defined in drop down box.rails 3

I am a newbie with rails and I am trying to fliter my index page on values selected by drop down box on index page
For Eg .In my index page I am having a drop down box showing employee names if user selects a value from drop down list the values of index page should filter with that employee name.
Note- Te Employee name is a cross reference field
My Controller Look like
def index
#complaints = Complaint.paginate(:page => params[:page], :per_page => 10)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #complaints }
end
end
My Index View Looks like
<%= select("employee", "employee_id", Employee.all.collect {|p| [ p.fullname, p.id ] }, { :include_blank => true }) %>
I have tried to answer with whatever I can understand from your question and
I am asssuming u dont want filtering through an ajax call and your complaint table consists of a column named employee_id.
In your index_view add
<%= form_tag 'controllers_index_path' , :method => "get", :id=> 'filter_employees_form' do %>
<p>
<%= select_tag 'employee_id', options_for_select(Employee.all.collect {|p| [p.fullname, p.id ] }, :selected => params[:employee_id]), :prompt => 'Select', :id => 'filter_employees' %>
</p>
<% end %>
Add the following code in the javascript file or add it at the end of your index page.
$(document).ready(function(){
$('#filter_employees').change(function(){
$('#filter_employees_form').submit();
})
})
In controller.rb
def index
#complaints = Complaint.get_complaints(params).paginate(:page => params[:page], :per_page => 10)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #complaints }
end
end
In complaint.rb(model)
def self.get_complaints(params)
conditions = ['']
conditions = ['complaints.employee_id = ?', params[:employee_id]] if params[:employee_id]
self.where(conditions)
end
Hope this is what you are looking for.

Resources