Rails syntax error, unexpected ')' - ruby-on-rails-3

This is going to be a really dumb question, and I almost hate myself for asking it, but here goes.
When I run my Cucumber test, I'm getting a "syntax error, unexpected ')'" with the following code:
inside my user model:
def member?(gallery)
array = []
self.groups.each do |group|
array << group.id
end
if array.include?(gallery.group.id)
true
end
end
And in my view:
<ul>
<% #galleries.each do |gallery| %>
<% if current_user.member?(gallery) %>
<li>
<%= link_to gallery.title, gallery %>
</li>
<% end %>
<% end %>
</ul>
EDIT: Here is the important part of the error in full:
~/Coding/Rails/galleryTest/app/views/galleries/index.html.erb:8: syntax error, unexpected ')', expecting keyword_then or ';' or '\n'
... current_user.member? gallery );#output_buffer.safe_concat('
... ^
~/Coding/Rails/galleryTest/app/views/galleries/index.html.erb:13: syntax error, unexpected keyword_end, expecting ')'
'); end
^
EDIT 2: Here is the error when removing the '=':
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id (ActionView::Template::Error)
./app/models/user.rb:18:in `member?'
I have tried a few different things, and I've got to be missing something really trivial. Another pair of eyes would be greatly appreciated.
Thank you very much.

<%= if current_user.member?(gallery) %>
should be:
<% if current_user.member?(gallery) %>
Not that there is no =, it means output and your code is trying to output the response of the if block.

Alright, here is what I have, and how it seems to be working:
In my user model:
def member?(gallery)
array = self.groups.collect { |g| g.id }
if array.include?(gallery.group_id)
true
end
end
In my view:
<% if user_signed_in? %>
<ul id="private_galleries">
<% #galleries.each do |gallery| %>
<% if current_user.member?(gallery) %>
<li>
<%= link_to gallery.title, gallery %>
</li>
<% end %>
<% end %>
</ul>
<% end %>
<ul>
<% #galleries.each do |gallery| %>
<% if gallery.group_id == nil %>
<li>
<%= link_to gallery.title, gallery %>
</li>
<% end %>
<% end %>
</ul>
My tests are running alright now, but they aren't passing, which is strange, as when I set up users with groups and galleries with groups and view them with the site running, they seem to be showing appropriately, which just means my tests are probably effed. That'll be a task for the morning, and probably another question on StackOverflow!

Related

Rails - SQL injection using .order to filter an index

In my index view, I'm iterating over a list of bookings.
Also, I added a dropdown menu with the option to sort by created_at: asc and created_at: desc.
index.html.erb
<div class="dropdown">
<button class="btn" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Sort by
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<p> <%= link_to "ASC", sort: :asc %> </p>
<p> <%= link_to "DESC", sort: :desc %> </p>
</div>
</div>
<% #bookings.each do |booking| %>
<%= booking.address %>
<%= booking.created_at %>
<% end %>
This is the way I am sorting the #bookings in the controller:
booking_controller.rb
class Users::BookingsController < ApplicationController
def index
#bookings = current_user.bookings.order(created_at: params[:sort])
end
end
I'm not really sure if this is the best solution and if it has some vulnerability in terms of SQL injections...
Generally using params for order is unsafe, see https://rails-sqli.org/#order
You can use sanitize_sql_for_order to sanitaze input for ActiveRecord#order
Passing key/value pairs to order(created_at: params[:sort]) is safe. Rails validates the direction. If you give it an invalid direction it will raise ArgumentError: Direction "..." is invalid. It's been this way since the syntax was introduced in Rails 4.
Passing a string to order as in order("created_at #{params[:sort]}") could be exploited in Rails 5 and earlier. See Rails SQL Injection for details. Rails 6 now sanitizes order arguments and will raise an exception if it detects funny business.
Rails 6, in general, is more robust against SQL injection. But it's up to you to sanitize your inputs before passing them to anything which accepts raw SQL.
Your view is not turning the bookings into a drop down menu. Instead, it's just a bunch of text. As lurker suggested, use a function like collection_select to generate the select and option tags for you.
<%= form_for #user do |f| %>
<%= f.collection_select :booking_id, #bookings, :id, proc { |b| "#{b.address} #{b.created_at}" , prompt: true %>
<%= f.submit %>
<% end %>
To tidy that up a bit, you can add a method to Booking to produce the label you want and replace the proc.
class Booking
def dropdown_value
"#{address} #{created_at}"
end
end
<%= form_for #user do |f| %>
<%= f.collection_select :booking_id, #bookings, :id, :dropdown_value, prompt: true %>
<%= f.submit %>
<% end %>

How to check if an ActiveRecord table entry is empty

I am not sure if the title of this question uses proper jargon, but hopefully this description will help. If you need more information, please let me know.
I am taking Chinese text from a form and splitting it into a 2d array of sentences and words. I then want to define all the words using dictionary entries in my database. Some of the words aren't in the database, so I want to check for that. What I am trying isn't working.
Here is my current code:
<% #lesson.parsed_content.each_with_index do |sentence, si| %> #iterate 1st dimension
<% sentence.each_with_index do |word,wi| %> #iterate 2nd dimension
<% sentence = sentence.to_s %>
<div class="word blt" id="<%= wi %>">
<div class="definition blt">
<% definition = DictionaryEntry.where(:simplified => word) %> #search by simplified chinese
<% definition.find_each do |w| %>
<% if w.definition == nil %> # PROBLEM: this never returns true.
<%= word %>
<% else %>
<%= w.definition %>
<% end %>
<% end %>
</div>
<div class='chinese blt'> <%= word %></div>
</div>
<% end %>
<% end %>
How can I change <% if w.definition == nil %> to return true if there is no definition in my database?
This is a shot in the dark but first I would switch your code around when you are converting the variable sentence to a string and looping through it. (unless you have a reason for it being that way)
<% sentence = sentence.to_s %>
<% sentence.each_with_index do |word,wi| %> #iterate 2nd dimension
Second, depending on how your data was put inside the database it might be an empty string instead of nil. So I would change the condition from
<% if w.definition == nil %> # PROBLEM: this never returns true.
to
<% if w.definition.blank? %> # Checks to see if definition is blank
Blank will check if its false, empty, or a whitespace string.
Finally, indentation is helpful especially when running loops and conditionals. It's easier on the eyes and helps you understand what's going on.
<% #lesson.parsed_content.each_with_index do |sentence, si| %>
<% sentence = sentence.to_s %>
<% sentence.each_with_index do |word,wi| %>
<div class="word blt" id="<%= wi %>">
<div class="definition blt">
<% definition = DictionaryEntry.where(:simplified => word) %>
<% if definition.empty? %>
<% word %>
<% else %>
<% definition.find_each do |w| %>
<%= w.definition %>
<% end %>
<% end %>
</div>
<div class='chinese blt'> <%= word %></div>
</div>
<% end %>
<% end %>
Let me know the results.

Activerecord iteration / append an exception at a certain position

I'm looking for a way to include a specific element at a certain position inside an iteration
Not experienced enough to use the right pattern (hence to search here on stack overflow with the right keywords, afraid of getting some duplicate question with this one)… but the base idea would as the following :
<% Post.all.each do |post| %>
<% if Post.all.index(post) == 5 # or any position %>
# render some html element (some kind of exception)
<% else %>
<%= post.title %>
<% end %>
<% end %>
But just without skipping any records in my post array
I'm not sure I have totally understood your request. each_with_index may help you, and if you don't use the else, you won't skip any records :
<% Post.all.each_with_index do |post, index| %>
<% if index == 5 # or any position %>
# render some html element (some kind of exception)
<% end %>
<%= post.title %>
<% end %>

Rails - Display a title only once in an .each block

Noob question here :)
I'm testing a variable, and if it exists, I'd like to display an .each loop with a title.
Of course, the title should be displayed only once. Is there a way to do it? Any best practice?
<%
#twitter_friends.each do |u|
if #user = User.is_a_member?(u.id)
%>
# HERE I'D LIKE TO DISPLAY THE TITLE ONLY AT FIRST ITERATION
<% #user.name %> is your twitter friend, and is a member.
<% end %>
<% end %>
Thanks !
I would normally recommend using each_with_index and checking for a zero index, but seeing as you have a conditional in the loop, you should use a check variable like so:
<% shown_title = false %>
<% #twitter_friends.each do |u| %>
<% if #user = User.is_a_member?(u.id) %>
# HERE I'D LIKE TO DISPLAY THE TITLE ONLY AT FIRST ITERATION
<% unless shown_title %>
<h1>My Title</h1>
<% shown_title = true %>
<% end %>
<% #user.name %> is your twitter friend, and is a member.
<% end %>
<% end %>

Preview button causes an error in my code

It use to work great under rails 2 and now moving to rails 3 as caused my code to have errors.
Error Message:
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
Slice of code:
<div id="archive-list">
<h4>Archives</h4>
<ul>
<% #archive_list.each do |item| -%>
<li><%= link_to(item[0], archive_url(:year => item[1], :month => item[2])) %></li>
<% end -%>
</ul>
there seems to be an issue with:
<% #archive_list.each do |item| -%>
with this line above
Any help would be great?
#archive_list is probably nil
do a puts #archive_list in the controller before rendering the view and check if it's nil
in the view you could do a <% if #archive_list.exists? %> before iterating over it, if it's an active record relation, or <% if #archive_list.blank? %> if it's something else (from the looks of the code it's the latter).