Rails / design array issue - ruby-on-rails

In my 'releases' show view I have the following code:
<% i = #release.id %>
<%= link_to image_tag('next.png'), release_path(i+1), :class => "editRelease" %>
Which takes the user to the next result in the releases table.
I am hoping to only display this 'next' button if an item exists in the array whose id value is one greater than the current release.
Happy to re-write this section of the view / place code in model,controller,helper definition.
Just trying to learn the correct rails way to solve this issue!
Thank you!

Records can be deleted, leaving gaps in your range of ID's, as such using a direct id+1 could point to a null record.
Instead you should define a next method in your model that safely returns the next object. If you don't have any ordering then you can use a query like the one posted in this answer.

Related

Conditionally Omit/Hide Button in Rails

My first time asking. I'm in an internship so I'm not that proficient in Rails. Currently I'm working in a code that isn't mine, it has no automated tests and no documentation whatsoever, so I spent lots of time trying to understand what the functions does before actually writing some code.
My question:
What I'm trying to accomplish is to hide/omit a button, under a set of conditions.
My research:
Already searched everywhere but with no luck to my specific problem. Tried the solutions here: How to disable all form_for input fields in Ruby on Rails app? and here: In Rails edit action form, hide a form field. Also read rails documentation about form helpers: https://guides.rubyonrails.org/v4.2.10/form_helpers.html
The problem:
There is an object called school that is divided into Schools and SchoolGroup, theoretically schools that have children should be SchoolGroup. I'm trying to omit the Delete button to every SchoolGroup that have Schools associated with it.
If I put like this nothing happens
<% if school.children.length < 1 %>
<%= button_to 'Delete', school, :data => {:confirm => 'Are you sure you want to delete this school?'}, :method => :delete, :class=>"btn btn-sm btn-delete" %>
<% end %>
However if I put like this
<% if school.children.length > 0 %>
every button disappears!
So, I'm inferring that every school probably have children, even though it shouldn't and I need to ask for a different condition. Or should I try a controller-wise solution? If so, what can I do?
I'm using ruby 2.2.10 and rails 4.2.10.
Thank you all for your time and any help :)
The school.children.length returns the size of the collection. So,new child is also counted.
length() Returns the size of the collection calling size on the target. If the collection has been already loaded, length and size are equivalent. If not and you are going to need the records anyway this method will take one less query. Otherwise size is more efficient.
You can use school.children.count to count the records that persisted in the database. This method call will fire a database query.

Pass values of checkboxes into an array?

Im trying to update someone else's Rails app. Right now, an HTML table displays values from a database. What i want is to be able to display a checkbox for each row and on submit, the values of the checkboxes are sent into an array (and the values shouldnt be "checked" or "unchecked", they should be the id's of the database row).
Heres what i have so far.
Checkbox : (message.id being a dynamic id)
<%= check_box_tag "message_ids[]", message.id %>
And on the controller:
#dispatches = Dispatch.find_by_message_ids(CODE TO RETRIEVE CHECKBOX ARRAY GOES HERE)
Any suggestions?
Have you tried inspecting the value of params?
Chances are this will work:
#dispatches = Dispatch.find_by_message_ids(params[:message_ids])
But if it doesn't, just look at what is being sent to your page. Try one of these:
logger.info(params)
or
raise (params.inspect)
or
render :inline => params.to_yaml
Check what you receive in your params because they're probably there if this is defined correctly. The current parameters are always logged in log/development.log which is something you should have open any time you're debugging something.

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