What are the data.* references in {wrap}bootstrap themes? - ruby-on-rails

I purchased a {wrap}bootstrap theme. In the process of moving the assets into my Rails 2.3.x app (don't laugh), I notice there are many places in the views and helpers where some data object is accessed. For instance:
def active(id)
if data.page.menukey == id
return 'active'
end
return ''
end
Where is this data object defined? Is it just a clumsy placeholder for people implementing the theme to replace with their own objects?

The data object you see in {wrap}bootstrap themes comes from MiddleMan "local data". MiddleMan is not required to implement a {wrap}bootstrap theme. You may wish to search and replace every instance of data with something meaningful to your application.

Related

Rails Limit Model To 1 Record

I am trying to create a section in my app where a user can update certain site wide attributes. An example is a sales tax percent. Even though this amount is relatively constant, it does change every few years.
Currently I have created a Globals model with attributes I want to keep track of. For example, to access these attributes where needed, I could simply do something like the following snippet.
(1+ Globals.first.sales_tax) * #item.total
What is the best way to handle variables that do not change often, and are applied site wide? If I use this method is there a way to limit the model to one record? A final but more sobering question.......Am I even on the right track?
Ok, so I've dealt with this before, as a design pattern, it is not the ideal way to do things IMO, but it can sometimes be the only way, especially if you don't have direct disk write access, as you would if deployed on Heroku. Here is the solution.
class Global < ActiveRecord::Base
validate :only_one
private
def only_one
if Global.count >= 1
errors.add :base, 'There can only be one global setting/your message here'
end
end
end
If you DO have direct disk access, you can create a YAML config file that you can read/write/dump to when a user edits a config variable.
For example, you could have a yaml file in config/locales/globals.yml
When you wanted to edit it, you could write
filepath = "#{Rails.root}/config/locales/globals.yml"
globals = YAML.load(File.read("#{Rails.root}/config/locales/globals.yml"))
globals.merge!({ sales_tax: 0.07 })
File.write(filepath) do |f|
f.write YAML.dump(globals)
end
More on the ruby yaml documentation
You could also use JSON, XML, or whatever markup language you want
It seems to me like you are pretty close, but depending on the data structure you end up with, I would change it to
(1+ Globals.last.sales_tax) * #item.total
and then build some type of interface that either:
Allows a user to create a new Globals object (perhaps duplicating the existing one) - the use case here being that there is some archive of when these things changed, although you could argue that this should really be a warehousing function (I'm not sure of the scope of your project).
Allows a user to update the existing Globals object using something like paper_trail to track the changes (in which case you might want validations like those presented by #Brian Wheeler).
Alternatively, you could pivot the Global object and instead use something like a kind or type column to delineate different values so that you would have:
(1+ Globals.where(kind: 'Colorado Sales Tax').last) * #item.total
and still build interfaces similar to the ones described above.
You can create a create a class and dump all your constants in it.
For instance:
class Global
#sales_tax = 0.9
def sales_tax
#sales_tax
end
end
and access it like:
Global.sales_tax
Or, you can define global variables something on the lines of this post

How to structure Util classes in RoR

I have a template that users can upload that generates a report. They can put special tags into the html template and it will replace with data from the db. Quick example:
<div class="customer-info">
<h1>{customer_name}</h1>
<h2>{customer_address_line1}</h2>
<h2>{customer_address_line2}</h2>
<h2>{customer_address_city}, {customer_address_state} {customer_address_zip}</h2>
</div>
I have a controller that looks up the customer and then parses the template and replaces the tokens.
Right now I have the parse code in the controller creating a fat controller. Not good.
But where should I move the code? Model folder? Create a Util folder and put it there?
Just not sure what the Rails Way would be.
I was curious about this too, and found a very similar discussion here. Honestly, I think it depends on how much parse code there is. If there are only a very few lines, then the model is a safe place. If it's going to be a large package, especially a re-usable one, the /lib/ folder may be a better bet for the parsing itself. However, you definitely should remove it from the controller, as you suggested.
I agree that the logic shouldn't be in the controller, but let's get a
little more specific about how you'd go about implementing this.
First, where are you storing your templates in the database? They
should be stored in their own model, let's call it
CustomerTemplate and give an attribute :template of type Text.
So now we have two types of objects, Customers and
CustomerTemplates. How to render a customer given a template? It
honestly wouldn't be terrible to just have a render function in
the CustomerTemplate model that takes a customer and renders it, but
it is putting some logic inside your app that doesn't strictly belong
there. You should separate out the "customer specific rendering logic"
from the "rendering my simple custom template language".
So, let's create a simple template handler for your custom language,
which I'm going to nickname Curly. This handler should know nothing about
customers. All it does is take a string and interpolate values inside
{}'s. This way if you want to add new template types in the future —
say, to render another model like an invoice — you can use the same
template type.
Templates in Rails are classes which respond to call and are
registered with ActionView::Template. The simplest example is Builder.
Here's a quickly written Template handler which renders Curly. The
call function returns a string which is eval'd, so the string has to
be valid ruby code. The string eval in scoped by the render call, so
it has access to any variables passed in via the { locals: {} }
option to render.
# In lib/curly_template_handler.rb
class CurlyTemplateHandler
def self.call(template)
src = template.source
"""
r = '#{src}'.gsub(/{([^}]*)}/) { |s|
local_assigns[$1.to_sym] || s
}
raw r
"""
end
end
Make sure the handler is initialized, and let's set it to listen for
the :curly type.
# In config/initializers/register_curly_template.rb
ActionView::Template.register_template_handler(:curly, CurlyTemplateHandler)
We need to add lib/ to autoload_paths so the class is loaded:
# config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
Finally, we can render our template in our view! I'm embedding the string here, but you'd really get it from a CustomerTemplate object:
<%= render(inline: "<h2>{customer_name}</h2><p>{customer_address}</p>",
type: :curly,
locals: { customer_name: #customer.name,
customer_address: #customer.address }) %>
DO NOT USE MY EXAMPLE CODE IN PRODUCTION! I left out a bunch of corner
cases which you'll need to handle, like sanitizing user input.

Keeping track of changes using rails - "changed?"

I am building a multi lingual website, using ruby on rails, where part of the content is supposed to be user generated and they are supposed to be able to create different versions of it for all languages. The language support is handled by i18n gem.
Part of their content is created using Markdown through http://daringfireball.net/projects/markdown/basics .
In my database I save: object.content_markdown_en, object.content_html_en, object.content_markdown_sv, object.content_html_sv and so on for the different locales.
Now if a user changes the content, new html is supposed to be generated. But it seems unnecessary to regenerate the html for all locales if he only made changes in one of the languages.
I thought there might be some way to use something like
if object.content_markdown_[locale]_changed?
generate_new_html
end
that can be run in a loop for all possible locales. But I can't find any nice ways of doing this.
How about:
[:en, :sv].each do |locale|
if object.send("content_markdown_#{ locale }_changed?".to_sym)
send("generate_new_#{ locale }_html".to_sym)
end
end
You can use send to call methods by name:
object.send("content_markdown_#{locale}_changed?".to_sym)
Your loop would look like this:
%w(en sv).each { |locale|
if object.send("content_markdown_#{locale}_changed?".to_sym)
generate_new_html
end
}
However, using a separate translation table might be a better approach.

Rails 3: Caching to Global Variable

I'm sure "global variable" will get the hair on the back of everyone's neck standing up. What I'm trying to do is store a hierarchical menu in an acts_as_tree data table (done). In application_helper.rb, I create an html menu by querying the database and walking the tree (done). I don't want to do this for every page load.
Here's what I tried:
application.rb
config.menu = nil
application_helper.rb
def my_menu_builder
return MyApp::Application.config.menu if MyApp::Application.config.menu
# All the menu building code that should only run once
MyApp::Application.config.menu = menu_html
end
menu_controller.rb
def create
# whatever create code
expire_menu_cache
end
protected
def expire_menu_cache
MyApp::Application.config.menu = nil
end
Where I stand right now is that on first page load, the database is, indeed, queried and the menu built. The results are stored in the config variable and the database is never again hit for this.
It's the cache expiration part that's not working. When I reset the config.menu variable to nil, presumably the next time through my_menu_builder, it will detect that change and rebuild the menu, caching the new results. Doesn't seem to happen.
Questions:
Is Application.config a good place to store stuff like this?
Does anyone see an obvious flaw in this caching strategy?
Don't say premature optimization -- that's the phase I'm in. The premature-optimization iteration :)
Thanks!
I would avoid global variables, and use Rails' caching facilities.
http://guides.rubyonrails.org/caching_with_rails.html
One way to achieve this is to set an empty hash in your application.rb file:
MY_VARS = {}
Then you can add whatever you want in this hash which is accessible everywhere.
MY_VARS[:foo] = "bar"
and elsewhere:
MY_VARS[:foo]
As you felt, this is not the Rails way to behave, even if it works. There are different ways to use caching in Rails:
simple cache in memory explained here:
Rails.cache.read("city") # => nil
Rails.cache.write("city", "Duckburgh")
Rails.cache.read("city") # => "Duckburgh"
use of a real engine like memcached
I encourage you to have a look at http://railslab.newrelic.com/scaling-rails
This is THE place to learn caching in all it's shapes.

break down a complex search query in Rails 3

I have a controller which has a lot of options being sent to it via a form and I'm wondering how best to separate them out as they are not all being used simultaneously. Ie sometimes no, tags, sometimes no price specified. For prices I have a default price set so I can work around with it always being there, but the tags either need to be there, or not. etc.
#locations = Location.find(params[:id])
#location = #locations.places.active.where("cache_price BETWEEN ? AND ?",price_low,price_high).tagged_with([params[:tags]).order(params[:sort]).paginate :page => params[:page]
I haven't seen any good examples of this, but I'm sure it must happen often... any suggestions? Also, even will_paginate which gets tacked on last should be optional as the results either go to a list or to a google map, and the map needs no pagination.
the first thing to do when refactoring a complex search action is to use an anonymous scope.
Ie :
fruits = Fruit.scoped
fruits = fruits.where(:colour => 'red') if options[:red_only]
fruits = fruits.where(:size => 'big') if options[:big_only]
fruits = fruits.limit(10) if options[:only_first]
...
If the action controller still remains too big, you may use a class to handle the search. Moreover, by using a class with Rails 3 and ActiveModel you'll also be able to use validations if you want...
Take a look at one of my plugins : http://github.com/novagile/basic_active_model that allows you to easily create classes that may be used in forms.
Also take a look at http://github.com/novagile/scoped-search another plugin more specialized in creating search objects by using the scopes of a model.

Resources