Display all versions of individual records in Papertrail - ruby-on-rails

I'm building a league system and currently it stores and updates the players 'elo score' depending on the result. Now, I'm trying to add in 'HighCharts' to display the players elo score over the season in a sweet looking line chart. Someone suggested I use Papertrail to store the updates and I have got that all installed.
Now here comes my problem, I can't seem to figure out how to spit out the users elo_score versions in an array easy for 'HighCharts' to use. I can get the last updates to elo_score:
Last updated score = <%= #player.versions.last.reify.elo_score %>
But I can't seem to find the syntax to spit out all the 'versions' for 'elo_score'. Something like "1000, 1020, 1043, 1020".
I've also tried:
<%= #player.versions.map { |version| version.reify.elo_score} %>
But this gives me "undefined method `elo_score' for nil:NilClass". While just <%= #player.versions.map { |version| version.reify %> spits out all information in the record and obviously not just the elo_score.
Can anyone help? Sorry if I've not made this clear, I'm absolute brand new to rails, and this is just a fun project in my spare time but I'm having a blast!
Thanks alot!

What you did here:
#player.versions.map { |version| version.reify.elo_score }
Is perfectly fine to take all those scores and put them in an array. The problem that you're getting (the nil:NilClass stuff) is coming because at least one reify is nil. That is, that some version doesn't have a reify.
If each version is supposed to have a reify, be sure to add that as a model validation, and find in your code where the reify is being set and see why it's nil.
If it's okay for a version to have a nil reify, you could accomplish it a number of ways, but the straightforward and explicit way would look like this:
elo_scores = []
#player.versions.each do |version|
unless version.reify.nil?
elo_scores << version.reify.elo_score
end
end
I would suggest putting this in to a method, like get_elo_scores, and then you could more easily call it like:
#player.get_elo_scores
EDIT For clarification from the comments:
Your User model (or Player model, whatever you named it) should have a method that looks like this:
def get_elo_scores
elo_scores = []
self.versions.each do |version|
unless version.reify.nil?
elo_scores << version.reify.elo_score
end
end
return elo_scores
end
I apologize for not making this clearer, but you won't have access to #player within this method because that only exists in the context of your controller and view. The above is now a proper instance method: it will call .versions upon itself, and the rest is fine. I also added an explicit return call at the end.
Now you will be able to call #player.get_elo_scores on any User (or Player) object.
Hope that helps!

Here's a one-liner version of #MrDanA's answer :
elo_scores = self.versions.map{|version| version.reify.elo_scores}
note that you can't check if version.reify.nil? though

Related

Can access ActiveRecord object, but not its attributes

I'm rendering a view in Rails using form_for and nested_form_fields. Here, #procedure_step is a record that has_many :procedure_step_actions, each of which belongs_to :error, which is a ProcedureError that has (among some relations to other models) an integer :code that I'm trying to access and print out to the page. Here's my template:
<%= form_for #procedure_step do |f| %>
<%= f.nested_fields_for :procedure_step_actions do |act| %>
<%= act.object.error.code %>
<% end %>
<% end %>
When I run this, I get undefined method 'code' for nil:NilClass. Okay, so my relations are messed up and I can't access act.object.error, right? Changing my template to display that instead yields #<ProcedureError:0x0000000ece02a8>, which is what one would expect of a functioning relation. Dumping its contents to the screen using debug shows all the attributes of the record, including code, but I still can't access it with the original template! Clearly act.object.error is not nil, so Rails telling me that act.object.error is nil doesn't make any sense to me.
Frustrated, I tried to work around the problem by using act.object.error.to_json. This printed the correct JSON for the record with all its attributes. Using JSON.load() on this gave me a correct Hash of all the attributes, but using [:code] to try to access the code gives me undefined method '[]' for nil:NilClass. Again, I know that object isn't nil, but Rails still refuses to allow me to access it.
Running out of ideas, I tried to use regular expressions to pull the code out of the raw JSON string. /"code":([0-9]+)/.match(act.object.error.to_json) returned #<MatchData "\"code\":69" 1:"69">, which is right. I used [1] to try to access the code number that was matched, but again I got undefined method '[]' for nil:NilClass.
Enough with ActiveRecord, I thought to myself. I decided to turn to raw SQL queries. I got the ID of the error in question using act.object.error_id, then printed that to the screen first to make sure I could access it. Luckily, I could. Then I inserted it into my SQL query with "... WHERE id = #{act.object.error_id}". I refreshed the page again and was greeted with a SQL error. It showed the final SQL query string I had generated, but it ended with WHERE id =. The ID of the error didn't get added to the string. ProcedureError.find(action.object.error_id) gave a similar error.
I'm totally out of ideas. What could possibly be preventing me from accessing one simple integer in so many different ways?
There are at least a couple of issues here. The first is that you probably want to be using fields_for, rather than nested_fields_for, if you're using 4.x.
The second is similar to what the first answer has indicated. You have a nested fields form, which allows you to nest one level in, but you are trying to nest two levels in. By addressing your law of demeter violation you should be able to make some more progress.
Debugging things like this you can get more information by throwing in a binding.pry or byebug right in your erb.
<%- binding.pry %>
Then reload the page. Your server will be stopped at that point in your code and you can play with variable values to learn more about what's going on.
One thing I can see right off the bat is you are violating Law of Demeter here
act.object.error.code
The form object obviously has to stay but you can delegate access to the subobjects by making a method on the procedure_step which can help with handling nulls, and other error cases.
Try delegating that first as I'm not sure if the scope that is created by nested_forms_for will allow the ActiveRecord::Relation object to perform properly. I'll double check locally.
A delegation might look like the following
class ProcedureStepActions
belongs_to :error
def error_code
#error.code
end
end
EDIT:
Other things that might be helpful are the version of Ruby and Rails you are using and any other additional gems or libraries.

each_with_index not working for an array rails [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
When each_with_index is used along with an array of active records returned from a query and when i call the attributes of the model. it says undefined method, for the attribute
Controller
#user_contact_query=Usercontact.select("*")
#available_contacts_array=Array.new
#user_contact_query.each do |variable|
#user_query=User.find( :all,:conditions => ["id = ?",variable.relator_id])
#available_contacts_array.push(#user_query)
end
View
<% #available_contacts_array.each_with_index do |variable, index| %>
<%= variable.email %>
<% end %>
Well, step by step, since this is rather bad code:
#user_contact_query = Usercontact.select("*")
the select part here is a bit strange, I would have used .all. Otherwise no problem here.
#available_contacts_array = Array.new
since in the next line you assign an array anyway there is no need to 'initialize' this variable here, you could just omit that line. (Most Ruby programmers would use [] to initialize an empty array in most cases)
#available_contacts_array = #user_contact_query.to_a
Assuming that we get some records back from the query we now should have an array with user contact objects. Again a simple .all would have had a similar effect as far as I understand what's going on. But assuming that Usercontact has email this is fine and what you expect it to be.
#user_contact_query.each do |variable|
#user_query = User.find(:all, :conditions => ["id = ?", variable.relator_id])
#available_contacts_array.push(#user_query)
end
Now if I get this right what you do is you go through all Usercontacts you found, find every User related to it (possibly more than one) and then attach the result at the end of the array of Usercontacts. As a result you have a mix of Users and Usercontacts in that array. (Which still would work in your view if both have email, since thanks to duck typing Ruby would not care. But most likely one of both is missing email). Also if more than one User is found then an array of users is pushed. And an array for sure has no email.
Ok, with your edit it becomes simple. When you use :all with find then what you get is not a record but an array of records (even if there us only one.). You can just do:
User.find(variable.relator_id)
which will then find a single record and push that in the array. Which I guess is what you expect it to do.
There would be better ways in Rails to do this but this would require the models to be defined properly what your use of relator_id makes look unlikely.
First off please post your full error message. Although Without seeing the error I can tell with certainty that the issue is caused by you calling a method on a nil object i.e you think a value exists where it actually does not.
Besides that you really really should take more care of your code. The code you have right now is just plain horrible. This is an equivalent of your code:
#available = []
UserContact.find_each do |contact|
#available << User.find(contact.relator_id)
end
An alternative is to use #inject
#available = UserContact.all.inject([]) do |list, contact|
list << User.find(contact.relator_id)
list
end
And the best solution would be to actually use ActiveRecord assocations here.
P.S your code does not make much sense anyhow. Why would you put users contacts and users both into that list?
Why don't you do just?
controller's helper:
#array = Usercontact.select( "*" ).map do| variable |
User.find( :all,:conditions => [ "id = ?",variable.relator_id ])
end
view's helper:
#array.each.with_index do| variable, index |
# ...
end
General note: you'be used in the #available_contacts_array variable mixed types, probably this lead to the error, please don't do in such matter.

Rails - Efficient way of finding entries with specific value in model

So I am trying to find all entries in my table that have a specific value in a particular column. The only way I can think off to do this is to look at each entry and see if it has the value but I was hoping there would be a more efficient solution - this gets unwieldy once you have a sizable database.
Does anyone have a better idea?
Update - I am creating an HTML table and I want to populate the table with all the entries in my model that have a certain value in a particular column. I am trying to do:
<%= render #users.where("column_name = 'value'") %>
as the answer below recommends but I get "undefined method `where' for nil:NilClass" error.
Update 2 - I am not sure why #users would be nil but I will try to figure that out later. For now, I tried
<% #user_message = User.where("column_name = 'value'") %>
<%= render #user_message %>
but it doesn't show any entries at all.
Update 3 - When I do, User.all in rails console, I get all the users so I know the data is there. However, when I do User.where("column_name = 'value'"), I get an empty array. I double checked the column name and value to make sure that the data was present.
Update 4 - Fixed! - I'm not sure why it didn't work in rails console but I got it to work in the site. I called my partial _user_message.html.erb. Apparently it still needs to be called _user.html.erb. Thanks for the help everyone!
Sounds like you want to do a where query, i.e.
#records = Model.where(:some_column => some_value)
Rails has excellent documentation, I suggest you take a look at the ActiveRecord Query guide:
http://guides.rubyonrails.org/active_record_querying.html
ian.

Why do I get nil objects iterating an array in an ERB template?

I am new to Ruby and currently trying a few experiments.
I am confused about these scripts:
<%=#myworlds[2].topic%>
and
<% id = 1 %>
<%=#myworlds[id+1].topic%>
#mywodrld is an instance of a model and topic is the field. When executing the first one, the program runs correctly. When I run the second script, I get the following error:
You have a nil object when you didn't expect it!
The error occurred while evaluating nil.topic
What causes the nil object?
When I try your approach, I can't replicate your problem. It works fine for me. My guess is that you might use the variable id somewhere else also and that when you call #myworlds[id+1].topic id has some other value. But as I said, only a guess.
However, I recommend that you use another syntax when looping through collections of models in Ruby. Try something like this:
<% #myworlds.each do |myworld| %>
<h1><%= myworld.topic %></h1>
<% end %>
And if you really need the value of the iterator, you could always go with:
<% #myworlds.each_with_index do|myworld, i| %>
Where i keeps track of the current index in the array. Another good thing with this is that id no longer exists in memory after the block ended.
Are you sure that you have no other differences between these two code snippets?
In your comment you say that you have #myworlds[#id+1], in the original question you say #myworlds[id+1] (local variable versus instance variable). Can you show the exact code?
Both scripts are OK. You can create variables in one <% %> block, and you can use them in another one (if they are in the same .erb file, of course).
The error message says that your array has no element with index #id+1 or id+1. You have to debug the value of the expression used for the index. I guess that there is somewhere some small mistake, like a typo.
What is the output of your debug(#myworlds[#id+1]) statement when #myworlds[#id+1].topic raises the error?
Also try to debug the value of id:
<pre>The id = <%= debug(id) %> (<%= id.inspect %>)</pre>
(Depending on your version of Rails you may want to use h( id.inspect ))
I'm guessing but for some reason id+1 is probably not equal to 2.
To check the value of id+1 you can do that :
raise (id+1).inspect
Inspect is very useful is you want to see what is in an object :)
I think I know how to solve the problem is. You are trying to each an array data from a model, but u use the parameter [#id+1]. No matter the "id" is global or local variable, but the problem is in the end of array, there are no array with index "id+1". You should add another parameter to prevent the unrecognized parameter.
Try this
if((#myworlds.length-1) > #id)
#id = #id+1
end
:D
It looks like you're looping over an array, but possibly using a for or while loop to accomplish it, rather than use an [].each. Your sample code doesn't give us enough information to work from so we're shooting in the dark attempting to help you.
Manually creating your index then trying to walk the array tends to run into problems where you either miss the first or last item, or you go too far and get the error you are seeing. Because each returns only the items in the array it can't do that.
Something like this might work better:
<% #myworlds.each do |world| %>
...
<%= world.topic %>
<% end %>
I didn't see the answer #DanneManne gave before I wrote my response. I think he's got the right solution.

Rails: Flatten array in parameter

I'm trying to flatten an array for my form.
def update
#tour = Tour.find(params[:id])
params[:tour][:hotel_ids][0] = params[:tour][:hotel_ids][0].split(',')
...
This results in:
"hotel_ids"=>[["1","2"]]
Naturally I want it to be
"hotel_ids"=>["1","2"]
My Form:
<%= text_field_tag 'tour[hotel_ids][]', nil %>
Hope anyone can help with this.
EDIT
I've gotten it to work, somehow. This might be a bad way to do it though:
I changed the text_field that get's the array from jquery to:
<%= text_field_tag 'tour[h_ids][]', nil %>
then in my controller I did:
params[:tour][:hotel_ids] = params[:tour][:h_ids][0].split(',')
And this works, I had to add h_ids to attr_accessor though. And it will probably be a big WTF for anyone reading the coder later... but is this acceptable?
This is ruby!
params[:tour][:hotel_ids][0].flatten!
should do the trick!
ps: the '!' is important here, as it causes the 'flatten' to be saved to the calling object.
pps: for those ruby-related questions I strongly suggest experimenting with the irb or script/console. You can take your object and ask for
object.inspect
object.methods
object.class
This is really useful when debugging and discovering what ruby can do for you.
Simply use <%= text_field_tag 'tour[hotel_ids]', nil %> here, and then split like you do in example.
What really happens in your example is that Rails get param(-s) tour[hotel_ids][] in request and it thinks: "ok, so params[:tour][:hotel_ids] is an array, so I'll just push every value with this name as next values to this array", and you get exactly this behavior, you have one element in params[:tour][:hotel_ids] array, which is your value ("1,2"). If you don't need (or don't want) to assign multiple values to same param then don't create array (don't add [] at the end of the name)
Edit:
You can also go easy way (if you only want answer to posted question, not solution to problem why you have now what you expect) and just change your line in controller to:
params[:tour][:hotel_ids] = params[:tour][:hotel_ids][0].split(',')
#split returns array and in your example you assigned this new array to first position of another array. That's why you had array-in-array.

Resources