Rails 3.0 - Where to put this logic? - ruby

I've got a Model Task with a member due_date. I'm using Chronic to take natural language input from the user and convert it to a Time, which then gets saved to the model.
I'm just not sure the best Rails, MVC-ish way to handle these use cases:
Display a formatted string (with some logic involved) to the user every time I show Task.due_date
Allow the user to input plaintext and have it parsed automagically everywhere they can edit Task.due_date
A helper method to format time was my first idea, like this:
<%= format_time task.due_date %>
combined with an overloaded setter on an accessor in my Task model, like this:
attr_accessor :due_date_string
def due_date_string=(string)
self.due_date = Chronic.parse(string)
end
This works everywhere I want it to except in my forms for editing:
<div class="field">
<%= f.label :due_date %>
<%= f.text_field :due_date_string %>
</div>
I don't know how to make the f.text_field element 'wire up' properly so that it saves to :due_date_string, but uses the helper method to display the string.
I don't necessarily need specific code examples, just looking for the kind of pattern that pro Rails-ers would use here.
Thanks!

With according to MVC conventions, data handle is about Model layer responsibility.
So you are going in right direction to do a setter (wrapper for due_date attribute):
You need to check that is attr_acessible that is access to get a data from params
def due_date_string=(string)
self.due_date = Chronic.parse(string) || Date.today
end
The representation logic to show the parsed date is Helper layer responsibility

In order to use:
f.text_field :due_date_string
Don't you also need a getter for the new attribute? e.g.,
def due_date_string
format_time self.due_date
end
Perhaps share what error or failure occurs when you use the custom text field. :)

Related

How do you convert a string to a variable with Ruby?

I am trying to add a link to a blog_post using in this case blog.link
If for example myblog.link = new_contact_path, it would be "new_contact_path".
In my view I am trying to create a link using
<%= #blogs.each do |blog| %>
<%= link_to blog.title, blog.link %>
<%end %>
I tried using #{blog.link} but that does not work.
I ended up trying something else. I will post it in the answer.
You cannot convert a string to a variable, for the simple reason that variables aren't objects in Ruby. If you wanted to convert a string to a variable, you would do that by either calling a method on the string, or by calling a method on some other object as passing the string as an argument. Either way, the variable would have to be returned by the method, but methods can only return objects and variables aren't objects.
Based on your case I guess you should use Object#send or Object#public_send methods:
'qwe'.send('upcase') # => "QWE"
What I did instead was made a helper method.
def blog_action_link(link)
case link
when "person"
new_person_path
when "place"
places_path
else
new_contact_path
end
end
Then I used the helper in my view instead.

Outputting method result to erb

I'm working on an application that creates random sentences. I have it working as a console application, and want to make a Sinatra app which lets me display the sentences on the browser.
I have a variable #grammar that is populated from a form. I want to pass this into a method a few methods which work together to take in a string and generate a random sentence from it using a lot of logic. My rsg.erb file looks like this.
Where 'The waves portend like big yellow flowers tonight.' is the output of the expand method. I would like to display this on the erb file so it is displayed on the browser.
How can I do that?
Can you try this:
<%= #grammar %>
<%-# Assigning values to the variables in first step %>
<%-
rds = read_grammar_defs(#grammar) #get text from file and parse
sds = rds.map { |rd| split_definition rd} #use split definition to make array of strings
tgh = to_grammar_hash(sds) #create hash
rs = expand(tgh) #create sentence
%>
<%-# Printing it in second step %>
<%= rs %>

put haml tags inside link_to helper

is it possible to add html-content inside a link_to helper in HAML?
i tried this, but all i get is a syntax error:
= link_to "Other page", "path/to/page.html"
%span.icon Arrow
expected output:
Other Page<span class="icon">Arrow</span>
You should use block
= link_to "path/to/page.html" do
Other page
%span.icon Arrow
If anyone is still using Rails 2.x on a project, it looks like the accepted answer returns the block, thus duplicating the link in the markup. Very simple change: use - instead of =
- link_to "path/to/page.html" do
Other page
%span.icon Arrow
The simplest way to do it is by using html_safe or raw functions
= link_to 'Other Page<span class="icon"></span>'.html_safe, "path/to/page.html"
or using raw function (recommended)
= link_to raw('Other Page<span class="icon"></span>'), "path/to/page.html"
Simple as it can get !!
Don’t use html_safe method unless you’re sure your string isn’t nil. Instead use the raw() method, which wont raise an exception on nil.

Rails 3.1 - Correct approach to remove a query from a view and process it in the controller or model

In a view I have the following:
<% #top_posts.each do |post| %>
<li>
<%= post.title %><br />
<%= link_to "Most popular comment", comment_path( post.comments.order("vote_cnt DESC").first )
</li>
<% end %>
I know it is considered poor form to have the post.comments.order("vote_cnt DESC").first query in a view. However, since I'm combining both post and comment data to create a single list item, I'm having a hard time understanding how to get this "combo-pack" of data built in the controller. Should I be constructing some sort of #hash in the controller and then iterate on #hash.each in the view? Is that the right approach?
Or is the job for a scope on my Post model? Is there some ActiveRecord magic that I'm missing that makes this easy? I'm still pretty rookie at RoR, and am just beginning to see just how much I don't understand.
What I'd do is add a method in my Post model to get the first comment according to your criterias. The view would then look like comment_path(post.relevant_comment).

Iterate Form fields

I have build a module to add translations for each standard topic. Theses topic got many standard options and you can translate it directly in page.
I got an issue with my form about the edit view.
When i display a translation it's repeat all value of the f.input :value each time he have one and i want it to display with the each of standard value.
The question is how i can iterate my input field :value in the form to display only once per standard value and not repeat all value translated by standard value.
when i want create a new one all workings fine. It's just about the iterate field who is repeated how many times he got a field in the table.
the gist for my code :
https://gist.github.com/266562670cd8dab28548
Change:
<%= #preference_topic.preference_topic_options.each_with_index do |option, index| %>
<%= f.fields_for option.preference_topic_option_translations.first, option do |translate_form| %>
to:
<%= #preference_topic.preference_topic_options.each_with_index do |option, index| %>
<%= f.fields_for option.preference_topic_option_translations.first || option.preference_topic_option_translations.build, option do |translate_form| %>

Resources