Change 'title' attribute in list view in rails_admin - ruby-on-rails

I use rails_admin to manage database of routers and ports. In ports index page I want to change title in <td> tag to node ip address.
This code I have in rails_admin now:
<td class="node_field belongs_to_association_type" title="cisco-node-pos-156">
<a class="pjax" href="/admin/node/85">
cisco-node-pos-156
</a>
</td>
And I want:
<td class="node_field belongs_to_association_type" title="192.168.1.1">
<a class="pjax" href="/admin/node/85">
cisco-node-pos-156
</a>
</td>
In this case node.name = "cisco-node-pos-156" node.ip = "192.168.1.1"
Illustration:
I copied index.html.haml from rails_admin source code and in this line
%td{class: "#{property.css_class} #{property.type_css_class}", title: strip_tags(value.to_s)}= value
I changed strip_tags(value.to_s) to strip_tags(value.ip.to_s) but error message was
undefined method `ip' for "0":String
here "0" is the ports name.

I would a a custom method to your model:
# in your model
def title_ip
# format stuff here
end
# in rails_admin config
list do
include_all_fields
field :title_ip
end
Or your could this in RA config
field :title do
formatted_value { bindings[:object].format_stuff_here }
end
I would not mess with HAML files.

Related

Check if ruby on rails model column is required

How can I check if a column for a Ruby on Rails column is required? I am building a process where people can import a CSV and match the headers in the file to relevant columns in the model. I can't guarantee that they will match so would rather the user could match them manually.
I'm ideally looking for something like Model.column_names[0].required?
If the column is required I want the user to be able to specify a generic value for all imports so that they don't fail unexpectedly (hence the unused input fields in the demo below).
I can upload the file contents and parse them, and have built a table where the user can select which CSV column matches which model column but would like to warn the use which are required. I am yet to create the actual import element but there are various other questions on SO with that well documented.
I've had a google and cant see anything, maybe I'm using the wrong search terms but any help would be appreciated.
Thanks in advance!
Controller:
require 'csv'
myfile = params[:file]
csv_text = File.read(myfile.path)
#csv = CSV.parse(csv_text, :headers => true)
#table_headers = Patient.column_names
View:
<% #table_headers.each_with_index do |header, table_i| %>
<tr>
<td>
<%= header %>
</td>
<td>
<select id="table_column[<%= table_i %>]"=>
<option value="skip">Skip</option>
<option value="custom">Custom</option>
<% #csv.headers.each_with_index do |column, file_i| %>
<option value="<%= file_i %>"><%= column %></option>
<% end %>
</select>
</td>
<td>
<input>
</td>
<tr>
<% end %>
If I get you right, you can use custom validation that will return specific error (that you want to share for user).
https://guides.rubyonrails.org/active_record_validations.html#performing-custom-validations
Basically you need to override validate! method.
https://apidock.com/rails/ActiveModel/Validations/validate%21
For identification of such record (that is not valid) you can user valid? method.
https://apidock.com/rails/v6.0.0/ActiveModel/Validations/valid%3F

Grails won't retrieve single item from list using get(params.id)

I have a table where you input information which is then displayed, when you click the name of it I want it to go to a new page where it only displays the item clicked and not everything.
Here is my controller...
class RecipeController {
def index() {
def recipe = Recipes.list() //Recipes is the Grails Domain
[recipe: recipe]
}
def newRecipeForm() {
}
def createRecipe() {
def r = new Recipes(name: params.name, course: params.course, diet: params.diet)
r.save()
redirect(action:"index")
}
def deleteRecipe() {
def r = Recipes.get(params.ID)
r.delete()
redirect(action:"index")
}
def showRecipe() {
def rec = Recipes.get(params.ID)
[recipe: rec]
}
}
My index.gsp where the recipe name is clickable which should redirect by ID to a new page where it just displays only that recipe info.
<g:each var="Recipes" in="${recipe}">
<tbody>
<tr>
<td><g:link action="showRecipe" id="${Recipes.id}">${Recipes.name}</g:link></td>
</tr>
</tbody>
</g:each>
and finally my showRecipe.gsp where the recipe should be displayed by itself...but it keeps displaying all of them that i add
<g:each var="rec" in="${recipe}">
<tbody>
<tr>
<td>${rec.name}</td>
</tr>
</tbody>
</g:each>
any guidance would be awesome! thanks
I could say that your first error is in your index.
It is likely that the Recipe.id that you have is retrieving all the id´s and sending them in the link. You should not use UpperCase in a property name, the compiler might think of the property as a Class. The code should be more like:
<tr>
<td><g:link action="showRecipe" id="${recipes.id}">${recipes.name}</g:link></td>
</tr>
</g:each>
Add a println(params) or log.info(params) in your show() action to print all your params and see exactly what you are receiving from your view.
Also be careful with your naming conventions. You might want to change recipe for recipeList or something, and recipes to recipeInstance or simply recipe. It will make the code more readable, and make it easier for us to help you.
EDIT
As #Nitin Dhomse said you only need to access the data of a single recipe so you don´t need to do
<g:each var="rec" in="${recipe}">
in your show.gsp.
It would be more like
<table>
<tbody>
<tr>
<td>${recipe?.id}</td>
<td>${recipe?.name}</td>
....
</tbody>
</table>
Also, you should either redirect in your show() action if you dont find the recipe Instance or access your properties like $(recipe?.name) in your show.gsp, otherwise you will get nullPointer Exceptions.

Using Nokogiri to select a block of HTML based on text?

I have the following block of HTML:
<tr>
<th>Consignment Service Code</th>
<td>ND16</td>
</tr>
What I'm ultimately trying to pull is that ND16 string, but to do that, I need to select the <tr> based on the text Consignment Service Code.
I'm using Nokogiri already to parse the HTML, so it'd be great to just keep using that.
So, how can I select that block of HTML based on the text "Consignment Service Code"?
You can do this:
require 'nokogiri'
doc=Nokogiri::HTML::parse <<-eot
<tr>
<th>Consignment Service Code</th>
<td>ND16</td>
</tr>
eot
node = doc.at_xpath("//*[text()='Consignment Service Code']/following-sibling::*[1]")
puts node.text
# >> ND16
Here's an additional try, which might help you to get going:
## parent node
parent_node = doc.at_xpath("//*[text()='Consignment Service Code']/..")
puts parent_node.name # => tr
## to get the child td
puts parent_node.at_xpath("//td").text # => ND16
puts parent_node.to_html
#<tr>
#<th>Consignment Service Code</th>
# <td>ND16</td>
#</tr>
Yet another way.
Use Nokogiri's css method to find the appropriate tr nodes and then select the ones that have the desired text in the th tag. Finally, work with the selected nodes and extract the td values:
require 'nokogiri'
str = '<tr>
<th>Consignment</th>
<td>ND15</td>
</tr>
<tr>
<th>Consignment Service Code</th>
<td>ND16</td>
</tr>
<tr>
<th>Consignment Service Code</th>
<td>ND17</td>
</tr>'
doc = Nokogiri::HTML.parse(str)
nodes = doc.css('tr')
.select{|el|
el.css('th').text =~ /^Consignment Service Code$/
}
nodes.each do |el|
p el.css('td').text
end
Output is:
"ND16"
"ND17"

Ruby on Rails: connect a function with the bootstrap botton

I am using this example for file uploader.
Now it works this way:
I upload a file, after the file is saved,the function(do_picture_analyse) calls R and produces a histogram(simplest version, in the more complicated version 2 packages have to be installed in R), picture of the histogram is saved. The problem is that if I want to upload 50 files, it takes lots of time to load 2 packages in R for each file separately(after_save callback).
What I need:
I upload a file, file is saved, I click on a button "Histogram" and the function do_picture analyses is called on all files that are in the database( It doesnt matter if some of the files have already been analyzed)
So I need only to know how to make an interaction between a button and a call of the function and nothing more.
My show.html.erb:
<script id="template-download" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-download fade">
<td></td>
<td class="name">
{%=file.name%}
</td>
<td class="nam">
{%=file.name%}
</td>
<td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
<td class="Pic">
<button class="btn btn-mini btn-info">Pic</button>
</td>
<td class="Hist">
<button class="btn btn-mini btn-primary" >Hist</button>
</td>
<td class="delete">
<button class="btn btn-mini btn-danger" data-type="{%=file.delete_type%}" data-url="{%=file.delete_url%}">
<i class="icon-trash icon-white"></i>
</button>
<input type="checkbox" name="delete" value="1">
</td>
</tr>
{% } %}
</script>
my upload.rb:
def to_jq_upload
{
"name" => (read_attribute(:upload_file_name)).split(".").first,
"size" => read_attribute(:upload_file_size),
"url" => upload.url(:original),
"delete_url" => upload_path(self),
"delete_type" => "DELETE",
"url_chip_image"=>read_attribute(:chip_image),
}
end
after_save :do_picture_analyse
def do_picture_analyse
if read_attribute(:chip_image)==nil
require 'rinruby'
myr = RinRuby.new(echo=false)
myr.filepath=upload.path(:original)
myr.fileurl=upload.url(:original)
myr.eval <<EOF
s=read.table(filepath)
for(j in nchar(filepath):1){
if(substr(filepath,j,j)=="/"){
savepath<-substr(filepath,1,j-1)
file.name<-filepath
file.name<-substr(file.name,j+1,nchar(filepath)-4)
break
}
}
file.name1<-paste(file.name,"image.jpeg",sep="_")
savepath<-paste(savepath,file.name1,sep="/")
jpeg(filename=savepath,width=250, height=250)
hist(s$V1)
dev.off()
EOF
self.update_attributes(
:chip_image => (((myr.fileurl).split("?").first)[6..-5]+'_image.jpeg')
)
end
end
EDIT:
do_picture_analyse can take a folder as a parameter and analyse all files inside it by loading the the packages only one time for entire folder.There are only two folders for the files(two different types of files, let say .txt and .blabla files will be saved either in the txt-Folder or in a blabla-Folder. The type of the folder is saved in the database as well. By clicking the button, two folders should be passed to the do_picture_analyse and it will do everything
Thanks in advance
you need to create a new route for this :
resources :name_of_your_controller do
# use this if you want a route like resources/:id/analyze (single file)
get :analyze, on: :member
# use this if you want a route like resources/analyze (multiple files)
get :analyze, on: :collection
end
then create a new action on your controller :
def analyze
# for single file analysis do something like this :
#file = File.find( params[:id] )
#file.do_picture_analyse
respond_to do |format|
# render what you need to render, js or html
end
# ... or do something like this for multiple file analysis :
#files = File.where( params[:search] )
#files.each {|f| f.do_picture_analyse )
# etc.
end
you can then link your button to your action :
# single file
<%= link_to "Histogram", analyze_file_path( file ) %>
# multiple files
<%= link_to "Histogram", analyze_files_path( search: your_search_conditions ) %>
PS: if your method needs a lot of processing power (if you use R, i assume that you have complex calculations involved), you should consider to extract it in a Worker to run it as a background task.
edit
response to your comments :
i think you should extract this method and make it a class method, that accepts one or more paths.
Then create a collection route that points to your controller ; in your controller action load the files according to some params and does something like this :
# find the directories to be processed :
paths = #files.map(&:folder_type).uniq
# pass them to your class method :
File.do_picture_analyse(paths)
It is even possible to create a class methods that automatically handles these two steps for all files in a relation :
def self.perform_analysis!
paths = all.map(&:folder_type).uniq # or uniq.pluck(:folder_type) on rails >= 3.2.1
do_picture_analyse(paths)
end
def self.do_picture_analyse( *paths )
# call R from here
end
then you can do :
File.where( your_search_params ).perform_analysis!
The short and sweet answer: in your show.html.erb write:
<td class="Hist">
<%= link_to 'Histogram', histogram_path, ;method => :post, :class => 'btn btn-mini btn-primary" %>
</td>
In your config/routes.rb add the following line
post '/histogram' => 'your-controller#histogram', :as => 'histogram'
THis means that the histogram_path will point to a controller named your-controller and call the action histogram. Please replace those with your names.
And then you should be good to go.
I have taken the liberty to propose a POST action, because I am assuming the action is not idempotent. If it is, you should use a GET.
Hope this helps.

take the table element while clicking on the same table element

I'm developing a project and I have a problem about this subject.
I'm constructing ruby on rails project which will provide listing students with name.
First of all , I will list my students information in a table and one part is missing.
When the user clicks on Student Name , another table will appear and show the other information of students(like course or GPA).
The table shows the students name ( this part is succeed.)
But I don't know how to post my variable when user clicks on the students name.
Moreover , I know fundementals of AJAX.But I don't know how to pass my variable while user clicks on students name in the table.
I don't use form , and I try to fix this problem with link_to_remote method but I can't post my variable.Because I can construct my table in for-loop according to my listing variable which contains whole database.I filter for getting only names and surnames in controller part of ruby on rails and i have listing variable for this.when in for-loop i use <%=student.name%> tag for displaying the part of my variable.and I must post this variable to page for filtering GPA or Course name according to names.I need something like link_to_remote method for posting my variable student.name
I'm waiting your help.
Code is below :
<table border="1">
<tr>
<th>
Name
</th>
</tr>
<% #listing.each do |student| %>
<tr>
<td>
<%=student.name%> <%= student.surname %>
</td>
</tr>
<% end %>
problem fixed ,:with => "'id=blabla'" in link_to_remote method

Resources