pass data from Rails to javascript in my case - ruby-on-rails

My controller:
class SchoolController < ApplicationController
def index
...
end
def edit
#school=School.find_by_id params[:id]
end
def check_teachers
#teachers = #school.teachers
#How to show teachers' names and titles in a lightbox by javascript ?
end
end
As you see above, I have a check_teachers method, inside which I got a list of teachers objects. Each Teacher object has name and title attributes.
A button click on the view will trigger the check_teachers method get called:
I would like to show all teachers name and title in a lightbox. I think I would need javascript to implement this. But I don't know how can I pass all the teachers' data from Rails to javascript and show the data in a js implemented lightbox...
Anyone can provide any help on this?

you can do it with ajax. Simpliest way is to use FancyBox(jquery plugin, http://fancybox.net/home )
your button code should looks like
<a id="ajax_button" href="<%= url_for :controller => :school, :action =>:check_teachers, :id=>#school.id %>">Check teachers</a>
then add this javascript
$(document).bind('load', function() { $("#various3").fancybox({ajax:{type : "GET" } })
and your method controller action should looks like
def check_teachers
#school = School.find(params[:id])
#teachers = #school.teachers
end
but it's better to move #school = School.find(params[:id]) to before_filter

Related

From an ActiveAdmin Sidebar how can I know what action I am in?

I wrote a custom ActiveAdmin Sidebar that adds context sensitive documentation to all the entities in my app.
I'd like the Sidebar to know what is the current controller action so to display more relevant information. Most importantly I'd like to know if the action is :index vs the other object specific actions.
To give you some more context, in case the action is :index I'd like to display a text that explains what the entity is, and if the action is :new or :edit I'd like to show a detail of all the object properties.
The code below gives you an idea of what I'm trying to achieve
module Help
class HelpSidebar < ActiveAdmin::SidebarSection
##help
def initialize
##help = YAML.load(File.read("app/admin/help/help.yml"))
super "help", sidebar_options
end
def block
-> do
# if action == :index
text_node ##help
.dig(collection.klass.to_s, "text")
# else
ul do
##help
.dig(collection.klass.to_s, "fields")
.each do |key, value|
li do
b "#{key.humanize}:"
text_node value
end
end
end
#end
end
end
def title
super
end
protected
def sidebar_options
{ if: proc { ##help.key?(collection.klass.to_s) } }
end
end
end
Thanks for your help

rails render action with that's params

My route for pages in routes.rb
get ":slug", to: 'site#pages'
my actions in site_controller.rb
def pages
render #page.page_template
end
def about
end
def contact
end
def content
end
def local_news
end
def global_news
#newscasts = Newscast.published.paginate(page: params[:page], per_page: 5)
end
and it's my error :)
Not see global_news action my #newscasts parameter
You need to define #newscasts inside pages method
#newscasts = Newscast.published.paginate(page: params[:page], per_page: 5)
Or you can write this in your controller above your methods.
before_action :global_news, only: [:pages]
Before action will run your global_news methods before every action defined inside only: in your case you can write (:pages) you can mention as many methods you want. If you remove only then global_news will run before every method.
This cast an error because you are just rendering the global_news. With render you are not executing the controller action. So #newscast is never set.
You can either use a before filter as in the other answer or call the method manually, because I think you are doing something dynamically here, right?
for example
def pages
global_news
render #page.page_template
end

ActiveAdmin modify existing controller action

In ActiveAdmin I am trying to edit instance variables in the show view. I have tried to do this with the following code per the ActiveAdmin docs:
#admin/job.rb
ActiveAdmin.register Job do
...
controller do
def show
#job = Job.find(params[:id])
#comment = Comment.new
#comments = #job.comments
end
end
...
This is resulting in a nilClass error when I try to use those variables in the ActiveAdmin show because they aren't really defined. Am I misunderstanding how the controller actions should be edited?
Try to use the show block not the show action in the controller:
https://github.com/activeadmin/activeadmin/blob/master/docs/6-show-pages.md#customize-the-show-page
ActiveAdmin.register Job do
show do |job|
attributes_table do
row :attributes_of_job
end
#you can also reach the comments like this: job.comments
active_admin_comments
end
end

Passing a variable between actions within same controller Rails

My show action:
def show
# Multiple keywords
if current_user.admin?
#integration = Integration.find(params[:id])
else
#integration = current_user.integrations.find(params[:id])
end
#q = #integration.profiles.search(search_params)
#profiles = #q.result.where(found: true).select("profiles.*").group("profiles.id, profiles.email").includes(:integration_profiles).order("CAST( translate(meta_data -> '#{params[:sort_by]}', ',', '') AS INT) DESC NULLS LAST").page(params[:page]).per_page(20)
#profiles = #profiles.limit(params[:limit]) if params[:limit]
end
There can be many different filters taking place in here whether with Ransacker, with the params[:limit] or others. At the end I have a subset of profiles.
Now I want to tag all these profiles that are a result of the search query.
Profiles model:
def self.tagging_profiles
#Some code
end
I'd like to create an action within the same controller as the show that will execute the self.tagging_profiles function on the #profiles from the show action given those profiles have been filtered down.
def tagging
#profiles.tagging_profiles
end
I want the user to be able to make a search query, have profiles in the view then if satisfied tag all of them, so there would be a need of a form
UPDATE:
This is how I got around it, don't know how clean it is but here:
def show
# Multiple keywords
if current_user.admin?
#integration = Integration.find(params[:id])
else
#integration = current_user.integrations.find(params[:id])
end
#q = #integration.profiles.search(search_params)
#profiles = #q.result.where(found: true).select("profiles.*").group("profiles.id, profiles.email").includes(:integration_profiles).order("CAST( translate(meta_data -> '#{params[:sort_by]}', ',', '') AS INT) DESC NULLS LAST").page(params[:page]).per_page(20)
#profiles = #profiles.limit(params[:limit]) if params[:limit]
tag_profiles(params[:tag_names]) if params[:tag_names]
end
private
def tag_profiles(names)
#profiles.tagging_profiles
end
In my view, I created a form calling to self:
<%= form_tag(params.merge( :controller => "integrations", :action => "show" ), method: :get) do %>
<%= text_field_tag :tag_names %>
<%= submit_tag "Search", class: "btn btn-default"%>
<% end %>
Is this the best way to do it?
Rails public controller actions correspond always to a http request. But here there is just no need for 2 http requests. A simple solution would be just creating to private controllers methods filter_profiles(params) and tag_profiles(profiles) and just call them sequentially.
You can also extract this problem entirely to a ServiceObject, like this:
class ProfileTagger
attr_reader :search_params
def initialize(search_params)
#search_params = search_params
end
def perform
search
tag
end
def tag
#tag found profiles
end
def search
#profiles = #do the search
end
end
As processing 30,000 records is a time consuming operation, it would make sence to perform it outside of the rails request in background. This structure will allow you to delegate this operation to a sidekiq or delayed_job worker with ease
Instance Variables
If you want to "share" variable data between controller actions, you'll want to look at the role #instance variables play.
An instance of a class means that when you send a request, you'll have access to the #instance variable as long as you're within that instance of the class, I.E:
#app/controllers/your_controller.rb
Class YourController < ApplicationController
before_action :create_your_var
def your_controller
puts #var
end
private
def create_your_var
#var = "Hello World"
end
end
This means if you wish to use the data within your controller, I would just set #instance variables, which you will then be able to access with as many different actions as you wish
--
Instance Methods
The difference will be through how you call those actions -
#app/controllers/your_controller.rb
Class YourController < ApplicationController
def action
#-> your request resolves here
method #-> calls the relevant instance method
end
private
def method
#-> this can be called within the instance of the class
end
end

ActiveAdmin action items depending on status of data

I want to hide the edit path if the object to edit has a certain status.
How can I do that?
I finally did it. I needed two things:
Redirect when access directly and hide buttons to the edit page.
To redirect when the user try to access directly to the edit page I use a before_filter:
before_filter :some_method, :only => [:edit, :update]
def some_method
redirect_to action: :show if status == something
end
To hide the buttons I do it like this:
ActiveAdmin.register Model do
config.clear_action_items!
action_item :only => [:show] , :if => proc { instance.status == something } do
link_to 'Edit', edit_model_path(instance)
end
end
If you are talking about hiding the edit link that is shown by default (along with the view and delete links) in the index action, you can customize the index view as follows:
ActiveAdmin.register Model do
index do
column :actions do |object|
raw( %(#{link_to "View", [:admin, object]}
#{link_to "Delete", [:admin, object], method: :delete}
#{(link_to"Edit", [:edit, :admin, object]) if object.status? }) )
end
end
end
Because the content of the column will be only what is returned by the column block, you need to return all three (or two) links at once as a string. Here raw is used so that the actual links will be displayed and not the html for the links.
This can be achieve using the following:
ActiveAdmin.register Object do
index do
column :name
actions defaults: true do |object|
link_to 'Archive', archive_admin_post_path(post) if object.status?
end
end
end
Note that using defaults: true will append your custom action to active admin default actions.
You could create a before_filter in your controller that only applies to edit action. It could check the status, and allow it to run or redirect_to depending on the return of the method.
Something like this in your applications controller:
def some_method
if foo.bar == true
redirect_to foos_path
end
end
Then in the beginning of your controller of question
before_filter :some_method, :only => :edit
A fully customizable solution would be to use an authorization adapter, either a custom one or a library such as pundit or cancan: https://activeadmin.info/13-authorization-adapter.html
My use case was around restricting actions based on the context (e.g. the user editing). I solved it locally like this:
controller do
def action_methods
if condition?
super
else
super - ['edit', 'update']
end
end
end
if u want to hide the "edit" link (in active_admin views) for object if the object holds some specific value, u can override the default view for the method and add condition before the link is displayed.

Resources