I have partial view that displays model-specific flash messages. The partial looks like:
app/views/mymodel/_flashpartial.erb
<% flash.each do |key, value| %>
<% if model_key = myModelFlash(key) then %>
<%= content_tag(:div, value, :class => "flash #{model_key}") %>
<% end %>
<% end %>
The myModelFlash method simply takes the key and checks for a particular prefix using a simple regex. It's located in
app/helpers/mymodelhelper.rb
module MyModelHelper
def myModelFlash( key )
m = /^_mymodel_(.*)/.match(key)
m[1] unless m.nil?
end
end
This works perfectly fine in my development and test environments. As soon as it goes onto Heroku, I get an error saying (ActionView::Template::Error) "can't convert Symbol into String" pointing to the call to match.
If I remove the call to myModelFlash from the view and simply display the key and value, that works just fine in terms of not erroring out, so at the very least the key and value are getting into the partial view just fine. For some reason the helper method thinks that the key being passed into it is a symbol and not a String.
Any ideas as to why this might be happening?
I suggest you just use key.to_s as a quick workaround.
The reason for your problem may be that some version of some component differs between your testing server and the production server.
If your tests pass, and your production environment crashes, that is a very bad situation.
You should compare the versions of ruby and all of the gems you are using. If you use 'bundler' then 'bundle list' gives a nice summary.
If you find out that all the versions are the same... Well, we will be looking for another reason.
Update
As it seems that the problem is caused not by the version differences, but by unexpected data in flash, which obviously in production environment may be different than in testing.
I suggest you change the myModelFlash method a little.
def myModelFlash( key )
if m = /^_mymodel_(.*)/.match(key.to_s)
return m[1]
end
end
The flash may contain different keys, some of them may be Symbols or really anything, so you must be prepared to handle all of them.
Converting the key parameter with .to_s should be a safe choice, but if you are sure that you always set the flash keys (I mean the keys related to this "_mymodel" issue) as Strings, you may change the first line of this method:
def myModelFlash( key )
if key.is_a?(String) && m = /^_mymodel_(.*)/.match(key.to_s)
return m[1]
end
end
And in your test, add a few other keys to your flash, and then test how the action handles them.
Related
I'm trying to find the last Econ_Result that belongs to a Econ_Report. I want to display the last record of the Econ_Result (ordered by "release_date") for each Econ_Report on the index view. In the controller I tried to take the list of all reports and find the last result using the following:
#econ_reports = EconReport.all
if #econ_reports.econ_results.size >= 1
#last_result = #econ_report.econ_results.last.release_date
end
econ_report.econ_results.size works on the index view when I place it in for each loop. When I try to call the value of the last record I run into issues with the fact that some reports don't yet have results (a temporary issue) so I threw in the if then check in the controller which is currently failing.
Thanks in advance for the rookie help.
Since #econ_reports is a collection of EconReport objects, you can't call an instance method like .econ_results on it. Instead, you can only call it on instances within the collection:
#econ_reports.each do |econ_report|
if econ_report.econ_results.any?
last_result = econ_report.econ_results.last
end
end
However, this can be terribly inefficient for a large collection of #econ_reports: both lines with econ_report.econ_results will query the database separately, meaning that you'll query the database independently for each econ_report in the collection. This is known as the N+1 query problem.
Luckily for you, as discussed in the link, Rails has a built-in solution to optimize this code so you'll only query the database once:
<% #econ_reports.includes(:econ_results).each do |econ_report| %>
<% if econ_report.econ_results.any? %>
<% last_result = econ_report.econ_results.last %>
# do something to display last_result
<% end %>
<% end %>
If you just want the release date you might try:
#last_result = #econ_report.econ_results.order('release_date DESC').limit(1).pluck(:release_date).first
It's worth noting that a Ruby if statement generally looks like:
if condition
end
The then is almost always omitted even though it is allowed.
I have a Controller with the function getAccounts where I look for certain accounts. My idea is to first show the number of results and then send the result array to the next function called showAccounts which generates the view. First of all I declared the result array as an instance variable. Then I tried to send with a form tag. It does not work ... Has anyone an idea?
def getAccounts
filter = '(uid='+params[:id]+')'
attrs = ['*']
#accounts=Array.new
conn = LDAP::Conn.new($HOST, $PORT)
conn.bind('cn=admin, dc=cippool-mb, dc=rwth-aachen, dc=de','DLPins!')
conn.perror("bind")
begin
conn.search($base, $scope, filter, attrs) { |entry|
setAttributes(entry)
}
rescue LDAP::ResultError
conn.perror("search")
exit
end
conn.perror("search")
conn.unbind
end
def showAccounts
end
The view where I send the data.
Es wurden <%= #accounts.size %> Accounts gefunden.
<%= form_tag :action => "showAccounts" do %>
<%= hidden_field_tag "accounts", #accounts %>
<%= submit_tag "Anzeigen" %>
<% end %>
I can also paste the view where I need this array, but I dont't think it's relevant for this question. I use Rails 3.2.7 and Ruby 1.9.2p0
If you want to pass some large amount of data between separate requests I would suggest using session, it's designed for such things.
If you debug(#accounts) you'll see what it passes -- something like <#0x7187237 Array> which is not what you want!
If you really want to pass in the accounts array, you'll need to serialize it to a text format to put in a hidden field. That's going to probably be a HUGE chunk of data though if #accounts is large.
That said, you could dump it to YAML or JSON, or use one of the serialization functions in Ruby or put it into a custom text format of your own (not recommended). Keep in mind then that you need to deserialize on the next page before you use it.
I'm assuming part of the wanting to pass it to the next step is to avoid an expensive LDAP request. You might want to look at putting in a lightweight cache -- redis for example -- to temporarily store the requests.
I feel like a moron asking this, but since I'm a new to developing, and I've been sitting here for an hour making something so simple work, I need to ask.
I want to show each Widget, but I keeping getting:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each
I tried using <%= debug #widgets %> and <%= #widgets.inspect %>, but nothing shows in my command prompt or browser.
I was trying to copy the each do statement on http://guides.rubyonrails.org/layouts_and_rendering.html
In my controller, called Pages Controller, I have:
def widgets_to_show
#widgets = Widget.all
end
In my view (pages#widgets_to_show), I have:
<% #widgets.each do |widget| %>
<%= widget.title %>
<% end %>
I have a widget model
I also have values in the widgets table
and I have a title field, so I'm not sure what I'm doing wrong
I'm trying to display it on a page that uses the High Voltage gem (https://github.com/thoughtbot/high_voltage) if that makes a difference.
As #DaveNewton suggested try accessing the widget from your console (not irb). Do the following from your terminal
# from your rails project dir
$ rails c
$ w = Widgets.all
$ puts w
$ w.each { |n| puts n.title }
If all of that works then we need more info to figure out what the problem is.
Edit:
My guess is that it has something to do with using high voltage on the same page. It's a gem for creating static pages so maybe that's interfering with showing your widgets - since what you're doing is something dynamic.
I got this question in a previous interview and couldnt do it , any idea?
What does this return? Where would it be used?
module ApplicationHelper
def show_flash
flash.map{|key, value| content_tag(:div, value, {:class => key})}
end
end
The 'flash' is a ruby-on-rails convention for storing information generated in one request (say, "invalid username" or "session not found" or "thanks for buying from us" or "cart updated") temporarily for being rendered into the next view from the client.
The flash is a hash-like object.
The .map method on hash-like objects will iterate over all items in the hash; in this case, the .map method is being passed a block that accepts two parameters (which it names key and value, because the key could be used to look up the value from the hash). The block uses the content_tag helper to output new <div> elements with the value from the hash and the CSS selector-class key.
So for a flash like this: {:name => "sars", :food => "pizza"}
It would emit HTML roughly like this: <div class="name">sars</div><div class="food">pizza</div>.
This is a clever little helper method that probably saves a fair bit of typing, but it makes some assumptions: order in the view doesn't matter, all the keys are either in the CSS already or the CSS is prepared to handle unknown class elements in a graceful way. This helper might only be used once in a template, but it'd still be helpful to have as a method that could be dropped into other projects later.
module ApplicationHelper
def show_flash
flash.map{|key, value| content_tag(:div, value, {:class => key})}
end
end
I'm new to rails after moving from PHP and am having no end to the frustrations, but hopefully there is a steep learning curve.
I was following a guide on how to make a twitter clone in rails, and have continued along that path making it more and more twitter like.
So I've got a 'users' page /users/show.html.erb which show all the posts from a user.
Now, if the currently logged in user is the same as the page owner, I'm trying to show the text box so that the user can add a new entry.
I've got what should be a very simple
<% if params[:id] == session[:user_id] %>
put the text box here
<% end %>
of course, that isn't working, but right above it I've output both the session[:user_id] and the params[:id], and the printout is exactly the same.
If I set the == to !=, I get the 'put the text box here' message.
any suggestions as to what I'm doing wrong?
I know these two values match, as I can see in the url and the output of the currently logged-in user. I've also output
-<% session[:user_id] %>-
-<% params[:id] %>-
so that I can see there is no gaps or spaces or other characters on either end of the parameters, and it all looks clean.
The output looks like this
-4c4483ae15a7900fcc000003-
-4c4483ae15a7900fcc000003-
which is the mongodb objectId of the user with dashes on either side to show that there are no spaces or anything.
Are you sure that both items are simple strings? What happens if you run, say
params[:id].to_s == session[:user_id].to_s
?
It could be like jasonpgignac pointed out. If you enter into IRB:
num = "7"
num2 = 7
num == num2 # => false
Make sure they are both of the same type. Putting <%= num2 %> will actually trigger the .to_s method... hence why the two appear to be equal when you output them in your .erb page.
Also, you might want to move that comparison into the controller. Something like:
#is_user_home = params[:id].to_s == session[:user_id].to_s
Then you can put in your view:
<% if #is_user_home %>
code here
<% end %>
It makes the code a little more easier to read.
As it was already stated, in most cases this kind of problems are caused by mismatch of compared types. Just adding to_s to both variables solves most cases.
Here check great source to learn more about all kind of comparisons used in Ruby.