Using the lib folder for application parts in rails - ruby-on-rails

there are some problems with Ruby on Rails I couldn't solve even spending hours and hours trying. I hope you guys can help me. The four questions are marked with Q1-Q4 at beginning of line.
I have an element in the view that I need more than once. For this reason there should be a separate module in the lib folder (so I can use it in an other project too).
What I need:
- A helper method that I can call automatically from any view.
- Since it requires more html stuff, I want to use an html file, which I render in the helper-method.
- Pass parameters to a javascript file.
- If the element is used, the JavaScript file must be included
- If the element is used, the CSS file must be included
Since it isn't easy to understand what I mean, I'll explain it again with a simple example (it's just an example, so don't think to much about its sence): Helper for creating a combo box with a view-helper or alternatively with a javascript method.
Clearly, I need
(html) - a text input field placed on top of a drop down box
(js) - a function that displays the selected item of the drop-down box in the text box.
(css) - the style of the text box positioned in front of the drop down.
(settings) - a settings file that initializes the element so that I can use it everywhere automatically.
The folder structure which I imagine:
lib
combo_box
combo_box_helper.rb
_combo_box.html.erb
combo_box.js
combo_box.css
At the combo_box-helper.rb I have 2 Methods:
combo_box_field(drop_down_content)
The method gives back a combobox using the partial. The array entries are available in the drop down box.
combo_box_js(drop_down_content)
The method must be called when a combo box is to be created using javascript. To make changes to the combobox only once, the element should also be created with the partial and passed to javascript.
Here appear the first problem:
Q1: At the first call (and only on the first call) of any method, it have to include the js and css file. What is the common way to do this?
Q2: How can I render a partial that is located in the lib folder and not in the app/view folder?
Q3: What is the common way to pass parameters to javascript?
My first try:
module ComboBoxHelper
def combo_box_field(drop_down_content)
output = check_first_call
output + render(:partial => 'combo_box', :locals => {:content => drop_down_content})
end
def
output = check_first_call
output + "<div class='hidden' data-combobox = '" + render(:partial => 'combo_box', :locals => {:content => drop_down_content}) + "'></div>"
end
def check_first_call
if #already_called
""
else
#already_called = true
javascript_include_tag("combo_box.js") + stylesheet_link_tag("combo_box.css")
end
end
end
Problems:
render-method doesn't work (it searches in app/view for the partial)
the call of check_first_call is ugly. especially as it returns a string.
the includes of javascript and css don't work (the files aren't in the asset pipeline)
The content of the .html.erb and .css files is self-explanatory.
Interesting part of the javascript file is my attempt to access parameters passed by Ruby on Rails:
$('div.hidden[data-combobox]').data("combobox")
If these problems are solved, only one thing is important:
How do I initialize the module correctly, so I use it automatically everywhere.
My first try:
I create a file at the folder config/initializers/init_combo_box with that code:
require_dependency 'combo_box/combo_box_helper'
ActiveSupport.on_load(:action_view) do
include ComboBoxHelper
end
Q4: Is this the common way? Do I have something to add to solve one of the above problems (for example the add the js- and css-files to the asset pipeline)?
Thanks for your help.

Related

rails 5.x: add nofollow to all links in 'sanitize'

I am working on a Rails application whose HAML templates frequently make use of a routine called sanitize. I have deduced from context that this routine sanitizes user-controlled HTML. Example:
# views/feed_items/_about.html.haml
%h3 Summary:
.description
= sanitize #feed_item.description
I want to make this routine add 'rel=nofollow' to all outbound links, in addition to what it's already doing. What is the most straightforward way to do that?
N.B. I am not having any luck finding the definition of this method, or the official configuration knobs for it. The vendor directory has two different HTML sanitizer gems in it and I can't even figure out which one is being used. This is a large, complicated web application that I did not write, and I barely understand Ruby, let alone all of Rails' extensions to it. Please assume I do not know any of the things that you think are obvious.
The sanitizer will strip out the rel tags if they exist.
I ran into a similar issue and added an additional helper method - clean_links to the ApplicationHelper module, and called it after sanitizing the content.
# application_helper.rb
def clean_links html
html.gsub!(/\\2')
html.html_safe
end
This method looks for all <a> tags, and adds rel="nofollow". The html_safe method is necessary or else the HTML will be displayed as a string (it's already been sanitized).
This solution treats all links equally, so if you only want this for links pointing outside the domain, you'll have to update the REGEX accordingly.
In your view: <%= clean_links sanitize(#something) %>
So, first the content is sanitized, then you add the rel="nofollow" tag before displaying the link.
Actually there's a built-in way:
sanitize "your input", scrubber: Loofah::Scrubbers::NoFollow.new

Instance variables in controller passed to bootstrap file input plugin

I'm using bootstrap3 and a particular plugin for bootstrap called file-input. I'm using file-input and paperclip to attach a picture of a restaurant to my Restaurant model.
One of the things I would like to do is have the ability for my users, when editing a restaurant image, to be able to see the old restaurant image (which is stored in #restaurant.image.url). After reading the documentation, I found that I can set a default image to file-input by passing in a source like so:
initialPreview: [
"<img src='/images/desert.jpg' class='file-preview-image' alt='Desert' title='Desert'>",
"<img src='/images/jellyfish.jpg' class='file-preview-image' alt='Jelly Fish' title='Jelly Fish'>",
],
What I'm stuck on is how do I get my #restaurant.image.url into the src attribute of a javascript array, that I can then pass on into the file-input plugin.
I found this question and it made it seem like if I turn my restaurant.js file into a restaurant.js.erb file I can just use ruby expressions.
javascript
("#image_upload").fileinput( initialPreview: ["<img src='<%= #restaurant.image.url %>' class='file-preview-image'>",]);
But #restaurant is blank in my javascript file. Anyone know why?
I am using rails 4, I don't know if that is the difference.
First and foremost, files located in the asset folder don’t have access to instance variables defined in the controller. However, views invoked by your controller do. One simple solution (although rails purists might behead me) would be to inline the javascript directly into your form partial.
in your _form.html.erb
<script>
$(document).ready(function(){
img_source = "#{defined?(#restaurant) && #restaurant.image.exists? ? #restaurant.image.url : image_url('default_image.jpg')}"
$("#image_upload").fileinput( initialPreview: ["<img src='"+img_source+"' class=\'file-preview-image\'>"]);
});
</script>
Note: I did add a default image (since you are using paperclip); modify accordingly.
More complicated solutions might involve gems such as gon which can help you pass variables to javascript functions.

Using components in admin-generator modules, it's possible? how?

I need to build a admin interface like this image show. In the past I use components for that purpose but now because the modules are generated trough admin-generator I don't know how to get this done. I check all this docs 1, 2, 3 but without any clue on how to do this. I also created a components.class.php under modules/sdriving_empresa/actions folder and include the component in the view include_component('sdriving_empresa') but get this error:
sfComponents initialization failed.
Any help?
Tabs and Partials, the easy way :)
One of the best possible javascripts for that purpose is Javascript Tabifier. Its easy
to install and play with it. You will find a lot of other Javascript and jQuery Tabbers, get the one you most like.
I would advise you to learn everything about symfony 1 partials in order to get the job easily done. Usually partials are a piece of code which is saved in an external file, and does is loaded later in any part of your code. Its like a variable with a lot of html and php code. Partials (the external files) allow also to receive input variables, so its easy to send them ids from related modules or tables.
Lets look at an example with Tabifier with two Tabs, information and Admin and two partials
editSuccess.php
$sModuleName = sfContext::getInstance()->getModuleName();
$sbasepathtabs = $sModuleName . '/tabs';
<div class='tabber' id='tabberglobal1'>
<div class='tabbertab' title='Information' >
<?php
include_partial($sbasepathtabs . '/_information/_information', array('form' => $form));
?>
</div>
<div class="tabbertab" title="Admin" >
<?php
include_partial($sbasepathtabs . '/_admin/_admin', array('form' => $form));
?>
</div>
</div>
Easily setup it:
Inside your module template folder, create the folder: /_tabs
Inside the folder /_tabs create the folder /_information and /_admin
Inside the folder /_tabs/_information create the file partial: _information.php
Inside the folder /_tabs/_admin create the file partial: _admin.php
Inside each one of those files partials write anything you want.
Those partials will receive the left variable form: array('form' => $form).
You can send to the partials more than one variable: array('form' => $form, 'variable2' => $formnumber2)
When you write a partial, in example the partial _information, you can easily get the form object and its values in the template with:
$id = $form->getObject()->getId();
For normal variables you wont need to call getObject.
Finally, take a deep look at the documentation of both things, symfony partials and Javascript Tabifier. They will solve you anything you need.
Backend Admin Generator:
Admin generator automatically generates all templates in the cache folder. Example:
cache\backend\prod\modules\autoTbPrueba1Backend\templates
cache\backend\prod\modules\autoTbPrueba1Backend\templates\indexSuccess.php
Most of its files are already partials, pay attention to the files who has the _ symbol in their name, they are partials. This means that most of the work is already done for you, and the only thing you will have to do is to override some of the partials (TbPrueba1Backend/list_header which is the file _list_header.php) or even the full template (indexSuccess.php) with the extended information you need.
In order to override backend generated templates and partials, you can copy those files to the template folder of your module:
apps\backend\modules\TbPrueba1Backend\templates
apps\backend\modules\TbPrueba1Backend\templates\indexSuccess.php
Set there any additional information you need, and if you dont see anything new while refreshing the web, remember to clear the symfony cache (symfony cc).
Once you have override the the templates and partials with the new information, the only thing you need now is to write/add those partials inside the div tabs created by your bootstrap framework as I described above.
For a good explanation of the admin generator:
Symfony 1.4 change admin generator actions or templates
http://www.slideshare.net/loalf/symfony-y-admin-generator
http://symfony.com/legacy/doc/jobeet/1_4/en/12?orm=Doctrine
You need the moduleName and the componentName in your include_component()
function include_component($moduleName, $componentName, $vars = array())
{
echo get_component($moduleName, $componentName, $vars);
}
Or maybe your module is in the wrong application. In that case, you may consider moving it in a plugin

Adding content to static files(pages)

I have several static files(pages), which are basically copies of my website pages source code, with the content changed.
These files support my website, (keeping the same format) in various ways.
For example the menu part is:-
<body>
<div id="menu">
<ul class="level1" id="root">
etc
etc. until
</ul>
</div>
Unfortunately every month or so my menu bar changes and I have to update each static file manually.
As each of my static files have the same menu.
Is it possible to have one menu file which can be updated and have the static files load them automatically.
I plan to have several more static files. So this would be a great help if someone can suggest how to accomplish this.
Oh yes. Use some javascript magic to load the menu bar upon page load and keep it in menu.html.
One solution may be to use a spider (wget --recursive) to download generated pages directly from your application. One command, and you have the full copy of your site. (just add some useful options, like --convert-links, for example).
The other option may be to write an after_filter in your controller, and write the generated content to a file (not always, but for example when you add a parameter ?refresh_copy=1). Maybe just turning on page caching would be suitable? But the problem will be that you will not be able to trigger the controller action so easily.
If you don't want the whole site copied, just add some specific routes or controllers (/mirrorable/...) and run the spider on them, or just access them manually (to trigger saving the content in the files).
I ended up creating one controller without a model.
rails g controller staticpages
I then created a layout file which imported the individual changes to the layout, via a "yield" tied to a "content_for" in the view files(static files(pages) in the "view of staticpages" (for example abbreviations, aboutthissite etc etc).
The rest of the static file loaded with the usual "yield" in the layout. Works a treat. No more updating the menu bar all done automatically.
To get to the correct static file I created a route using:-
match 'static/:static_page_name'=> 'staticpages#show' (or in rails 2.x:-
map.connect 'static/:static_page_name', :controller=> "staticpages", :action=> "show"
"static_page_name" variable accepted anything after "/static/" in the url and passed it to the controller "staticpages" in which I set up a show action containing:-
def show
#static_page_name = params[:static_page_name]
allowed_pages = %w(abbreviations aboutthissite etc, etc,)
if allowed_pages.include?(#static_page_name)
render #static_page_name
else
redirect_to '/' #redirects to homepage if link does not exists
end
end
I then only had to change the links in the website. (e.g.<%= link_to " About This Site ", '/static/aboutthissite' %>)
and viola! its all working.

Where should I place code which generates Excel spreadsheet?

I am using spreadsheet gem to generate native Excel file. This is not CSV, XML file. Ordinary Ruby code is used to create the file. The generated Excel file (kept in StringIO) is forwarded to a client using send_data method. I need send_data method because of its parameters like disposition.
The data for the Excel is retrieved in controller method just like for ordinary HTML, JS requests. However I placed the code to generate the spreadsheet in controller protected method. Not in a view as I should.
Is there an elegant solution to above problem compliant with MVC design pattern?
Update: There is no popular and accepted by all solution to above problem but at least I know all possible ideas.
The lib directory is meant as a place for code that isn't strictly part of the MVC structure, but will be needed by multiple models, views, or controllers. It can be brought in with a require when needed.
However, if you only need the code in a single controller, you'd be just as well off putting it into that controller's helper. That way it's auto-loaded and at your fingertips. Plus, it makes sense: it's code to help a specific controller.
Either way, don't leave it in your controller or try to wedge it into your view.
Create an excel library in your lib folder in which you include your xls generation routine as well as a method that overrides ActionController's render method.
In a model that should be rendered as xls implement a method called to_excel method which generates a hash that you can provide to your xls routine.
Doing it this way, you'll get something really "Railsy". In your controller you'll just call
render :xls => #model
i just did this today for my app hope this helps for an excel o/p ; never used any plugin
controller:
def export
pr = Program.find(session[:pr_id])
headers['Content-Type']="application/vnd.ms-excel"
headers['Content-Dispositon']='attachment;filename="report.xls"'
#voucherdatas = Voucherdata.find_all_by_pr_name(pr.pr_name)
end
view: export.html.erb
manager
"reports/voucherdatas", :object =>#voucherdatas %>
routes.rb
map.resources :reports ,:collection =>{:export =>:get}
whereever u want the link give
link_to "Export As Excel", export_reports_url, :popup=>true

Resources