Change default Rails text_area helper rows/cols - ruby-on-rails

I am finding myself specifying :rows => 5 on all my text_area form helpers, So I looked up its definition and found the DEFAULT_TEXT_AREA_OPTIONS to be the hash dictating these options. However, the hash has this freeze method on it and I looked it up, it means it can't be changed. If you could recommend me some options to try to do a app-wide :rows => 5 for all text area, I'd really appreciate it.
Thanks

You can do:
Write own helper:
def readable_text_area(form, method, options = {})
form.text_area(method, options)
end
or redefine text_area method delegating to original text_area with proper options
or extend ActionView::Helpers::InstanceTagMethods with your own method "my_text_area" and delegate to original text_area with proper options. Then you can use "f.my_text_area(...)"
or change DEFAULT_TEXT_AREA_OPTIONS:
.
module ActionView::Helpers::InstanceTagMethods
remove_const :DEFAULT_TEXT_AREA_OPTIONS
DEFAULT_TEXT_AREA_OPTIONS = { "cols" => 40, "rows" => 5 }
end
Option 1 is most clean. 2 & 3 patch known public interface - seems acceptable. 4 patches internals - risky.

I'm a fan of:
class ActionView::Helpers::InstanceTag
silence_warnings do
DEFAULT_FIELD_OPTIONS = {}
DEFAULT_TEXT_AREA_OPTIONS = {}
end
end
As #gertas warned this is patching internals so it comes with risk. These constants have moved around in Rails occasionally. But overall it is not a huge deal. Either:
You are using CSS for width and height so these attributes are being ignored anyway. In that case all you are doing is saving a few useless characters from moving across the screen. If it stops working you just spend a few extra characters until you notice it.
You are using these attributes so when the hack stops working it becomes obvious (the field size changes) and you can fix it quickly.
So it does come with risk. But not much and it the most straight forward way to adjust these defaults.

Related

HTML "class" and "id" attributes using hyphens instead of undescores in Rails 4

Rails fills the id and class of an element generated with various input tag helpers (text_field for example) by itself. For example, in a form_for(#athlete), adding a text_field :height generates
<input name="athlete_height" ... />
I am a strong advocate of the use of hyphens in HTML ids and classes (and in CSS selectors consequently) (by reading MDN, because I like to write using the conventions dictated by the language - like in data-stuff - and because it's just better looking).
I read here and there that in Rails you can't fix this. This would be quite disappointing.
Do you know a way around this problem?
I'm afraid, underscores are hardcoded. From https://github.com/rails/rails/blob/master/actionview/lib/action_view/helpers/form_helper.rb, lines 446-450:
options[:html].reverse_merge!(
class: as ? "#{action}_#{as}" : dom_class(object, action),
id: (as ? [namespace, action, as] : [namespace, dom_id(object, action)]).compact.join("_").presence,
method: method
)
you can always provide your own id and class, or patch code of ActionView, which may be hard, tedious and error-prone
Recently ran into this very same situation and #lobanovadik has a good solution: just write your own helper method.
# app/helpers/dom_helper.rb
module DomHelper
dom_id_helper(model)
dom_id(model).dasherize
end
end
# view.html.erb
<%= link_to "Text", path, id: dom_id_helper(#model) %>
#=> Text
This has the benefit of not monkey-patching Rails or messing with any default methods/configuration. Thus, you won't "break" any updates to Rails.
It also gives you greater flexibility because you can now use both dashes or underscores depending on the situation. For instance, let's say there's a gem that expects IDs to have underscores...you won't break it.
As a personal preference, I always append _helper to all my own helper methods, so that I know it's a helper method and that it came from me and not from Rails (easier to debug).

Globally delimit numbers in rails app?

Is it possible to format all numbers in a rails app to be delimited?
I don't really think this is an i18n issue, as I'm fine with the default delimiter/separator characters. I'm simply trying to avoid putting number_with_delimiter(value) all over my views.
I always want numbers to be displayed as delimited. Always.
So far I've tried extending the Fixnum class with code cribbed from the number_with_delimiter method:
class Fixnum
def delimit(delimiter=",", separator=".")
begin
parts = self.to_s.split('.')
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
parts.join separator
rescue
self
end
end
end
> 98734578.delimit
=> "98,734,578"
> 223.delimit => "223"
So this is a step in the right direction- I like the dot notation as well as the slightly shorter method name. But I'd like to apply this to all instances of a Fixnum inside of a view without having to call .delimit.
Is this a bad idea? Should I be worried about implications this will have on numbers outside of the view context? Is there a better way to accomplish this goal?

Override to_xml for all objects in Rails 3

Looking to override to_xml method for everything in my app and having a tough time.
The reason is pretty trivial, I need to get rid of the :indent formatting it does by default. I've heard the arguments that "this is a view" problem, and that I should just override to_xml in my models where I need this.
The problem is that I return this stuff programmatically and having :skip_types set makes my responses incorrect. They're incorrect when you have an empty array, and you end up with:
\n
Suddenly it's a string value read by the client cotaining \n (<< there's a bunch of whitespace there, too, but stack overflow doesn't seem to like it). I also don't like the idea of having to override the same thing in 30 places.
That said, the fix is really easy, I just can't seem to put it in the right place. Just looking for help on where to put this. And a second set of eyes on my fix would be appreciated, too.
My fix is
alias __old_to_xml to_xml
def to_xml(options = {})
options.merge!(:indent => 0)
__old_to_xml(options)
end
I generally agree with the apprehension others have about the approach, but I think you could monkey patch it by adding a file to config/initializers with the following:
module ActiveRecord::Serialization
alias __old_to_xml to_xml
def to_xml(opts={})
__old_to_xml opts.merge(:indent => 0)
end
end
If you're on Rails 3, I believe you'll want ActiveModel::Serializers::Xml instead of ActiveRecord::Serialization, but no guarantees.

Rails way to offer modified attributes

The case is simple: I have markdown in my database, and want it parsed on output(*).
#post.body is mapped to the posts.body column in the database. Simple, default Activerecord ORM. That column stores the markdown text a user inserts.
Now, I see four ways to offer the markdown rendered version to my views:
First, in app/models/post.rb:
# ...
def body
markdown = RDiscount.new(body)
markdown.to_html
end
Allowing me to simply call #post.body and get an already rendered version. I do see lots of potential problems with that, e.g. on edit the textfield being pre-filled with the rendered HMTL instead of the markdown code.
Second option would be a new attribute in the form of a method
In app/models/post.rb:
# ...
def body_mardownified
markdown = RDiscount.new(body)
markdown.to_html
end
Seems cleanest to me.
Or, third in a helper in app/helpers/application_helper.rb
def markdownify(string)
markdown = RDiscount.new(string)
markdown.to_html
end
Which is used in the view, instead of <%= body %>, <%= mardownify(body) %>.
The fourth way, would be to parse this in the PostsController.
def index
#posts = Post.find(:all)
#posts.each do |p|
p.body = RDiscount.new(string).to_html
#rendered_posts << p
end
end
I am not too familiar with Rails 3 proper method and attribute architecture. How should I go with this? Is there a fifth option? Should I be aware of gotchas, pitfalls or performance issues with one or another of these options?
(*) In future, potentially updated with a database caching layer, or even special columns for rendered versions. But that is beyond the point, merely pointing out, so to avoid discussion on filter-on-output versus filter-on-input :).
The first option you've described won't work as-is. It will cause an infinite loop because when you call RDiscount.new(body) it will use the body method you've just defined to pass into RDiscount (which in turn will call itself again, and again, and so on). If you want to do it this way, you'd need to use RDiscount.new(read_attribute('body')) instead.
Apart from this fact, I think the first option would be confusing for someone new looking at your app as it would not be instantly clear when they see in your view #post.body that this is in fact a modified version of the body.
Personally, I'd go for the second or third options. If you're going to provide it from the model, having a method which describes what it's doing to the body will make it very obvious to anyone else what is going on. If the html version of body will only ever be used in views or mailers (which would be logical), I'd argue that it makes more sense to have the logic in a helper as it seems like the more logical place to have a method that outputs html.
Do not put it in the controller as in your fourth idea, it's really not the right place for it.
Yet another way would be extending the String class with a to_markdown method. This has the benefit of working on any string anywhere in your application
class String
def to_markdown
RDiscount.new(self)
end
end
#post.body.to_markdown
normal bold italic
If you were using HAML, for example in app/views/posts/show.html.haml
:markdown
= #post.body
http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#markdown-filter
How about a reader for body that accepts a parse_with parameter?
def body(parse_with=nil)
b = read_attribute('body')
case parse_with
when :markdown then RDiscount.new(b)
when :escape then CGI.escape(b)
else b
end
end
This way, a regular call to body will function as it used to, and you can pass a parameter to specify what to render with:
#post.body
normal **bold** *italic*
#post.body(:markdown)
normal bold italic

Rails View DRYness - Do you set variables in the view or just make clean methods?

I have a view in which I have the same link 3 times (actual view is large):
%h1= link_to "Title", model_path(#model, :class => "lightbox")
= link_to "Check it out", model_path(#model, :class => "lightbox")
%footer= link_to "Last time", model_path(#model, :class => "lightbox")
That model_path(#model, :class => "lightbox") call, though fairly clean, can be made even leaner wrapping it in this (maybe you had some more options, so doing this was worthwhile):
def popup_model_path(model)
model_path(model, :class => "lightbox")
end
My question is, I am having to recalculate that path 3 times in a view. What is the preferred way of a) DRYing this up and b) optimizing performance?
I think setting variables at the top of the view might be a good idea here:
- path = model_path(#model, :class => "lightbox")
-# ... rest of view
It's almost like mustache in the end then. What are your thoughts?
I think using variables in the view is a good idea here. Since these method calls are exactly the same.
The solution as proposed by Matt i prefer in some cases, but not in this case, because i find it confusing: the fact that it is cached in the method is not clear, and if i want to see two different models in one page i still get the first cached link for both models.
So in this case I would choose the somewhat more explicit approach and assign it to a variable in the view.
I really hate putting variables in the view. I would change your helper to
def popup_model_path(model)
#model_path ||= {}
#model_path[model] ||= model_path(model, :class => "lightbox")
end
to "memoize" it, and just keep the three function calls.
This seems like a possible case of premature optimization. Making a function like popup_model_path is a fantastically DRY idea. Especially if that bit of code, however terse it may be originally, is going to be used frequently across multiple views. However, worrying about the performance impact of calculating the path 3 times in one view is, in my opinion, needless. Unless we're talking about something that is going to be used dozens or hundreds of times per view, and you're expecting many many simultaneous users, and the app is running on a shared server or something I really don't see what you have currently having any perceptible impact on performance.
As a general rule, I do my best to avoid variables in my view code. They make it harder to read and with a few exceptions (such as variables directly related to loops that display stuff like lists) I feel they kinda go against the whole MVC concept as I understand it.
I think above all else you should strive for code that is easily readable, understandable, and maintainable; both for yourself and others not previously familiar with your project. popup_model_path as you have it now is simple enough to where anyone who knows Rails can follow what you're doing. I don't see any need to make it any more complicated than that since it's not terribly repetitive. I wish I could find this excellent blog post I remember reading a while ago that made the point that DRYing up your code is great, but it has its limits, and like all great things the law of diminishing returns eventually kicks in.

Resources