New to Rails and SQL and I'm trying to access associations in my app.
I have an itinerary web app where users can come and download itineraries. As part of the process they can leave reviews with their thoughts. I want the owner of the review to be able to edit or delete her review after the thought if need be, but the following Active Record Association is returning an error for #itinerary.reviews.user_id:
undefined method `user_id' for #<Review::ActiveRecord_Associations_CollectionProxy:0x007fb969392978>
Inside my itineraries_helper:
def user_is_reviewer?
#itinerary = Itinerary.find(params[:id])
!!current_user.id == #itinerary.reviews.user_id
end
In my view:
<div class = "review-container">
<h2>What Travelers Thought</h2>
<% if #itinerary.reviews.count > 0 %>
<% #itinerary.reviews.each do |review| %>
<div class = "reviews">
<div class = "star-rating" data-score= <%= review.rating %> ></div>
<p>
<%= review.comment %>
</p>
<% if user_is_reviewer? %>
<% link_to "Edit", edit_itinerary_review_path(#itinerary, #review) %>
<% end %>
<% end %>
</div>
Questions:
Why does Review.first.user_id work but not itineraries.reviews.user_id
What SQL command will achieve what I am looking for?
If I can use SQL, what SQL resource can I pick up to learn more? If not, whats a better way?
Review.first will return your a Review Object and you are accessing the user_id associated with it by Review.first.user_id
while
itinerary.reviews
is returning a collection of all the reviews that belongs to a particular itinerary and it is collection of active record objects and you were trying to access the user_id from active record collection which is not going to work.
You can solve it by passing review id to your helper method
def user_is_reviewer?(review_id)
review = Review.find(review_id)
!!current_user.id == review.user_id
end
In your view updating the helper method to have review id passed
<% if user_is_reviewer?(review) %>
<% link_to "Edit", edit_itinerary_review_path(#itinerary, #review) %>
<% end %>
OR else you can simply go without a helper method as you already have a review object like following in your view
<% if current_user.id == review.user_id %>
<% link_to "Edit", edit_itinerary_review_path(#itinerary, #review) %>
<% end %>
Related
I have this code in the (ERB) view file:
<% if current_page?(some_object_path(some_object)) %>
<%= f.submit "Create Some Object", class:'btn btn-success'%>
<% else %>
<%= f.submit "Update Some Object", class:'btn btn-info'%>
<% end %>
and this:
<%= form_tag import_some_object_path, multipart: true do %>
<%= file_field_tag :file, class: "" %>
<%= submit_tag "Import CSV", class: "btn btn-info " %>
<% end %>
Now, the issue is that I have several of these different paths relating to respective classes (tables in the database). I don't want to replicate these codes in all 9 Class views in the app. Is there a way to refactor this so I can reference the code in just one location (say, a _partial), and then rails knows what object to insert in the some_object field depending on say, the current_page? Is there a magic wand way to do this?
(I have really scoured the internet but I can't find a solution. It may be that I am using the wrong search terms though)
I am taking a rails class at my University and I am trying to create a search form which will show the results on the same page rather than show a different page of results. Is this something simple to do? I am creating a museum app with artifacts for each museum but I want the user to search artifacts from either page.
On my routes.rb I have
resources :artifacts do
collection do
get 'search'
end
end
On my museum index I have the code below that he gave us but not sure how to tweak the get routes for the same page.
<%= form_tag search_artifacts_path, :method => 'get' do %>
<p>
<%= text_field_tag :search_text, params[:search_text] %>
<%= submit_tag 'Search' %>
</p>
<% end %>
<% if #artifacts %>
<p> <%= #artifacts.length %> matching artifacts. </p>
<h2> Matching Artifacts </h2>
<% #artifacts.each do |a| %>
<%= link_to "#{a.name} (#{a.year})", a %><br />
<% end %>
<% end %>
Yes, this is easy. Just have the index page return the search results if params[:search_text] is present - this way you don't need a new route or a different page.
class ArtifactsController < ApplicationController
def index
#artifacts = Artifact.search(params[:search_text])
end
end
class Artifact < ActiveRecord::Base
def self.search(query)
if query
where('name ILIKE ?', "%#{query}%")
else
all
end
end
end
So then your form looks like:
<%= form_tag artifacts_path, :method => 'get' do %>
<p>
<%= text_field_tag :search_text, params[:search_text] %>
<%= submit_tag 'Search' %>
</p>
<% end %>
Edit:
So what you really want to do is any page you want to search, include a form which makes a request to that same page.
Then in each of those controller methods just put this line of code:
#artifacts = Artifact.search(params[:search_text])
and that will populate the #artifcats array with only artifacts that match the search query.
Try using "Ransack" gem. It can also perform some more powerful searches.
Im working on a rails app where a user has the ability to upload photos. When a user uploads their photos it will appear on their profile. Everything works great besides when there is no photos created then I am unable to view the user profile page because of the photo being nil.
here is my show method in the users_controller.rb
def show
#user = User.find_by_id(:id)
#photo = #user.photos.find(params[:id])
end
Here is my show.html.erb
<% for photo in #user.photos %>
<%= photo.title %>
<%= photo.description %>
<%= image_tag photo.image_url(:thumbnail) %>
<%= link_to "Show", photo %>
<br>
<% end %>
How can I bypass this error?
The code for your action seems wrong...
It should be this:
def show
#user = User.find(params[:id])
##photo = #user.photos.find(params[:id])
end
I commented out the third line on purpose, because I'm not sure what it is you want to do there, yet.
The #user variable needs to be defined using params[:id], given that this is the show action for the UsersController, so the id for the user will be passed through as params[:id].
But then you go and use this to find the photo for the user, which is what confuses me... the Photo record's id attribute is probably not going to be the same as the User record's id attribute.
So what is it?
You can replace the code in your show.html.erb with this:
<% if #user.photos %>
<% for photo in #user.photos %>
<%= photo.title %>
<%= photo.description %>
<%= image_tag photo.image_url(:thumbnail) %>
<%= link_to "Show", photo %>
<br>
<% end %>
<% end %>
The problem is, when the user doesn't have any photos, #user.photos returns nil so you have to check for that first.
On my web app I have a login page which is in the Pages Controller called welcome.html.erb
Inside it has a simple form for login and a simple for for sign up, both on the same page.
If the user signs up with wrong credentials (like password confirmation wrong, or length of password and etc) the controller that handles this is the new method in the Users Controller.
Inside the new method it checks if a user is created, and if not I'd like it to return to the welcome method in Pages Controller, passing to it the errors that were created during the user's creation.
It seems that if I do a
redirect_to root_path
The error count of the signup is reset when returning to the root page. If instead I call some other action of the users controller I do see the errors.
But since all of the html code is in the welcome view I don't want to replicate the code in the users controller views as well..
Is there a way to pass that errors data to the pages controller?
The partial for the error is
<% if object.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(object.errors.count, "error") %> prohibited this <%= object.class.to_s.underscore.humanize.downcase %> from being saved:</h2>
<p>There were problems with the following fields:</p>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Which I call using
<%= render 'shared/error_messages', :object => f.object %>
redirect_to welcome_path
(Or whatever the actual path is.)
From the Users controller I called
flash[:errors]=#user.errors
and then I changed the partial to be
<% if object.any? %>
<div id="error_explanation">
<h2><%= pluralize(object.count, "error") %> prohibited this <%= object.class.to_s.underscore.humanize.downcase %> from being saved:</h2>
<p>There were problems with the following fields:</p>
<ul>
<% object.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Which I called using
<%= render 'shared/error_messages', :object =>#user_errors %>
That solved the issue for now..
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 %>