I'm creating an app that allows users to access different courses on video (each course has its own 4 or 5 videos, and each video has its own page).
I created a courses_controller which allows me to index and show the courses stored in the database.
Courses_controller.rb :
class CoursesController < ApplicationController
before_action :set_course, only: [:show]
skip_before_filter :verify_authenticity_token
before_filter :authorize , except: [:index, :show]
def index
#courses = Course.all
end
def show
end
private
# Use callbacks to share common setup or constraints between actions.
def set_course
#course = Course.find(params[:id])
end
def authorize
unless User.find_by_id(session[:user_id]) and User.find_by_id(session[:user_id]).active == true
redirect_to subscriptions_path, :notice => "Vous devez souscrire à un abonnement pour avoir accès a cette page"
end
end
Each course is stored in a seeds.rb file.
courses/index.html.erb lists the courses, courses/show.html.erb shows the presentation of a specific course. These 2 parts are OK.
How to create a link to the current course from the show.html.erb page?
I mean, if I have "course1" and "course2", the link will redirect "( show.html.erb )course1 presentation" to "( ?.html.erb )course1 first video" and "( show.html.erb )course2 presentation" to "( ?.html.erb )course2 first video", etc.
Any idea?
On your index you are doing right.
def index
#courses = Course.all
end
Now in index view you should have link to show page related to each course.
<% #courses.each do |course| %>
<tr>
....
....
<td><%= link_to( 'show', course_path(course) ) %></td>
</tr>
<% end %>
To show all videos related to a course in show page start from first video, You should use kaminari or will paginate. So your show action should look like.
def show
#course = Course.find(params[:id]) #if you want to show any detail of course
#videos = #course.videos.paginate(:page => params[:page], :per_page => 1)
end
Now you will get first video of course in first show request and on each pagination click. you will see next one.
<%= #course.name %>
<%= #videos.first.url %> ##because paginate return array always
## to paginate videos
<%= will_paginate #videos %>
Related
I have a resource PracticeQuiz which has a nested child called PracticeQuestion. I can successfully create both of them, and can go to the next question, but what I would like is that when a user is taking a quiz, the "previous" and "next" buttons should only show questions that are in the parent id.
For example:
foo.com/practice_quizzes/mountains/practice_questions/1-11,24,25
The user should be able to go from question 1-11, then at 11 it should go to 24,and if the user wants back to 11 once they get to question 24. At question 25 it should either not show the button or say that there are no more questions.
foo.com/practice_quizzes/fruits/practice_questions/12-23,26,27,31
foo.com/practice_quizzes/animals/practice_questions/28-29,30,32
(Please note that this is about the amount of questions in a quiz, because questions will be deleted or updated or changed in the future. I don't want to make sorting ID based, unless this is a bad idea and i don't know why)
What I need is for the user to be able to navigate the show.html.erb page by clicking previous or next, and ONLY be shown the questions that are associated with a quiz, no matter what their ID is, and for the app to not crash when it detects that there is no question at the very first or last, or if a new question is being added.
Here's what I've tried so far:
views/practice_question.show.html.erb
<%= link_to 'next', practice_quiz_practice_question_path(#practice_quiz, #practice_question.next) %>
models/practice_question.rb
class PracticeQuestion < ApplicationRecord
belongs_to :user, optional: true
belongs_to :practice_quiz
def previous
PracticeQuestion.where("practice_quiz_id = ? AND id < ?", self.practice_quiz.id, self.id).first
end
def next
PracticeQuestion.where("practice_quiz_id = ? AND id > ?", self.practice_quiz.id, self.id).first
end
end
models/practice_quiz.rb
class PracticeAnswer < ApplicationRecord
belongs_to :practice_question
end
controllers/practice_questions_controller.rb
class PracticeQuestionsController < ApplicationController
before_action :authenticate_user!
before_action :set_practice_quiz, only: [:show, :edit, :update, :destroy]
before_action :set_practice_question, only: [:show, :edit, :update, :destroy]
def index
if params[:practice_quiz_id]
#practice_questions = PracticeQuiz.friendly.find(params[:practice_quiz_id]).practice_questions
else
#practice_questions = PracticeQuestion.all
end
#all_practice_questions = PracticeQuestion.all
end
def show
#current_practice_question = PracticeQuestion.find(params[:id])
end
def new
#practice_quiz = PracticeQuiz.friendly.find(params[:practice_quiz_id])
#practice_question = PracticeQuestion.new
end
def edit
end
def create
#practice_quiz = PracticeQuiz.friendly.find(params[:practice_quiz_id])
#practice_question = #practice_quiz.practice_questions.build(practice_question_params)
#practice_question.user = current_user
respond_to do |format|
if #practice_question.save
format.html { redirect_to [#practice_quiz, #practice_question], notice: 'Practice question was successfully created.' }
format.json { render :show, status: :created, location: #practice_question }
else
format.html { render :new }
format.json { render json: #practice_question.errors, status: :unprocessable_entity }
end
end
end
private
def set_practice_question
#practice_question = PracticeQuestion.find(params[:id])
end
def set_practice_quiz
#practice_quiz = PracticeQuiz.friendly.find(params[:practice_quiz_id])
end
def practice_question_params
params.require(:practice_question).permit(:question, :explanation, :flagged, practice_questions_attributes: [:answer])
end
end
How can I do previous/next for practice_questions to ONLY show questions that are associated with the id of its parent? And to avoid any errors/pitfalls such as reaching the first or last question of the quiz?
Thanks very much in advance :)
P.S - Some have said this is not a nested resource as far as controllers/models/views go, but In my routes.rb i did this, so doesn't that make it a nested resource?
resources :practice_quizzes do
resources :practice_questions
end
I imagine two options:
You can use the index in the Quiz controller to get all Questions for this Quiz, and show them in the index view with pagination. If you set pagination to 1 item per page, you get exactly what you want.
PracticeQuizzesController
def show
#quiz = PracticeQuizz.find_by(id: params[:id])
#questions = #quiz.practice_questions.paginate(:page => params[:page], :per_page => 1)
end
views/practice_quizzes/show.html.erb
<%= #quiz.name %>
<%= #quiz.description %>
<%= will_paginate #questions %>
<%= render #questions %>
views/practice_questions/_practice_question.html.erb
<%= practice_question.text %>
etc...
Second option
In the show method for the Question, get the next and previous questions, to show on the show view
PracticeQuestionsController
def show
#question = PracticeQuestion.find_by(id: params[:id])
#next = #question.practice_quizz.practice_questions.where("id > ?", #question.id).order("id").first
#prev = #question.practice_quizz.practice_questions.where("id < ?", #question.id).order("id desc").first
end
views/practice_questions/show.html.erb
<% if #next %>
<%= link_to 'next', practice_quiz_practice_question_path(#practice_quiz, #next) %>
<% end %>
I have a user profile controller called "userinfo" and it's corresponding view. The userinfo index is the root path. In the homepage(which is the userinfo index), I have a link that takes you to the user profile page. It is giving me this error when I click on the image on the view page:
My routes are:
My userinfos_controller:
class UserinfosController < ApplicationController
before_action :find_userinfo, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def index
#userinfors = Userinfo.where(:userinfo_id => #userinformation_user_id)
end
def show
#myvideo = Video.last
end
def new
#userinformation = current_user.userinfos.build
end
def create
#userinformation = current_user.userinfos.build(userinfo_params)
if #userinformation.save
redirect_to root_path
else
render 'new'
end
end
def edit
end
def update
end
def destroy
#userinformation.destroy
redirect_to userinfo_path
end
private
def userinfo_params
params.require(:userinfo).permit(:name, :email, :college, :gpa, :major)
end
def find_userinfo
#userinformation = Userinfo.find(params[:id])
end
end
and my view is:
<%= link_to image_tag("student.png", class: 'right'), userinfo_path(#userinfors) %>
I thought maybe I must include ':index' in the 'before_action :find_userinfo' at the top of my controller. If I do that, the homepage doesn't even load and it gives me this error:
Try below code:
controller
def index
#userinfors = Userinfo.where(:userinfo_id => #userinformation_user_id) #pass id instead of object #userinformation_user_id
end
view
<% #userinfors.each do |u| %>
<%= link_to image_tag("student.png", class: 'right'), userinfo_path(u) %>
<% end %>
Your problem is that you're trying to do perform a lookup based on something that's not an ActiveRecord (database) attribute.
Your root goes to UserinfosController which expects #userinformation_user_id but I can't tell from your code where that comes from.
You need to define your route in order that this will be expecting for an specific param, maybe the user id, and then you're able to add the value within your view, in a link_to helper:
You could modify your routes.rb to expect an id as param:
get '/user_infors/:id', to: 'userinfos#index', as: 'userinfo_path'
Then in your controller, use a find to "find" in the database the user with such id. If you'd like to use where then that would give you a relationship with all the userinfos with the id being passed as param.
If you want so, then use Userinfo.where('userinfo_id = ?', params[:id]):
def index
#userinfors = Userinfo.find(params[:id])
end
And then in your view you can access to #userinfors:
<% #userinfors.each do |user| %>
<%= link_to image_tag 'student.png', class: 'right', userinfo_path(user) %>
<% end %>
I think you could define the index to get all the userinfors and a show method to get an specific one, as you're trying to do.
I cannot seem to find the problem. In my venues show template, I want to show the venue name, and under that, I list all the venues in the database
<%= venu.name %>
<% #venus.each do |v| %>
I get the error that #venus is nil... but it is defined in my controller:
undefined method 'each' for nil:NilClass
venues_controller.rb
class VenuesController < ApplicationController
before_action :find_venue, only: [:show, :edit, :update, :destroy]
def index
#venus = Venue.all
end
def show
render :layout => nil
#venus = Venue.all
end
def new
#venu = Venue.new
end
def create
#venu = Venue.new(venue_params)
#venu.save
end
def edit
end
def update
end
def destroy
end
private
def venue_params
params.require(:venue).permit(:name, :phone, :address, :description, :type)
end
def find_venue
#venu = Venue.find(params[:id])
end
end
I have a resources :venues route in my routes.rb.
I am not sure what is causing this problem.
In your show method, you should render at the end
def show
#venus = Venue.all
render :layout => nil
end
Remove render :layout => nil from your show action.
And in your view, you need to use the instance variable #venu instead of venu
<%= #venu.name %>
I wonder why you use two instance variables for action show
#venu (via find_venue before_filter) & #venus via the action itself.
Best practice would be removing this line from action show, since show action normally used to show details for one element from a list.
#venus = Venue.all
and use #venu set by the before_filter instead.
But if you do want to keep both then re-order the lines in show action
#venus = Venue.all
render :layout => nil
Also, change the venu to #venu in the show.html.erb and if you like correct the typo in the instance variables #venu => #venue :) (Could happen to any of us)
Usually in the index method, it should show all the venus, and in the show method it would show detailed view of each venue.
Try setting something like this:
def index
#venus = Venue.all
end
def show
render :layout => nil
#venue = Venue.find(params[:id])
end
now in show.html.erb you should be able to use
#venue.name
and in your index.html.erb, you can iterate over the venus like so:
<% #venus.each do |v| %>
<%= link_to v do %>
<%= v.name %>
<% end %>
<% end %>
The above answer is correct. You can use #venus = Venue.all in your show view but because you render first it throws you an error. Just render at the end.
So i want from this dropdown, to be able to select or basically filter, some drawings based on the workcategory they are at. Both models (Drawings and Workcategories) are connected with has_many drawings and belongs_to workcategories. The drawing holds the workcategory.id as foreign key, and i want to filter by it.This is what i've tried to build
<% #workcategories.each do |workcategory| %>
<li><%= link_to workcategory.name, workcategory_list_path(workcategory.id) %></li>
<% end %>
While in the drawings controller i've added these :
before_filter :list
def list
#drawingsz = Drawing.order("drawings.id ASC").where(:workcategory_id => #workcategory.try(:id))
end
The problem is, whenever i press one of the workcategories inserted, it shows me all the drawings. I've tried from this basic variation to others, including some routings. Oh and talk about routings, i have this :
resources :workcategories do
get :list, :controller => :drawings
resources :drawings
end
resources :drawings
any ideas ? i've browsed the forums a lot last night, and also the routes pages on the official docus, but i just can't get myself around it. I would like the pages to be basically like : /workcategory.name/drawings. Thank you !!
update - added controller
class DrawingsController < ApplicationController
before_action :find_drawing, only: [:edit, :update, :destroy]
before_filter :list
def index
#drawings = Drawing.all.order("created_at DESC")
end
def new
#drawing = Drawing.new
end
def create
#drawing = Drawing.new(drawing_params)
if #drawing.save
flash[:notice] = "Drawing created"
redirect_to(:action=>'index', :drawing_id => #drawing.id)
else
#drawings = Drawings.order()
render('new')
end
end
def edit
end
def update
if #drawing.update_attributes(drawing_params)
flash[:notice] = "Drawing updated."
redirect_to(:action=>"index")
else
render("edit")
end
end
def destroy
#drawing.destroy
redirect_to drawings_path
end
def list
#drawingsz = Drawing.order("drawings.id ASC").where(:workcategory_id => #workcategory.try(:name))
end
private
def find_drawing
#drawing=Drawing.find(params[:id])
end
def drawing_params
params.require(:drawing).permit(:name, :description, :image)
end
end
View update
This is the new view update - which doesn't work, due to another error.
<% #workcategories.each do |workcategory| %>
<li><%= link_to workcategory.name, {:controller => 'drawings', :action => 'list', :workcategory_id => workcategory.id } %></li>
<% end %>
I've updated the list to this :
def list
#workcategory_id = params[:workcategory_id]
if #workcategory_id
#drawingz = Drawing.find(params[:workcategory_id]).workcategory_id
end
end
Now i get the error
Couldn't find Drawing with 'id'=2015
Which is odd, because 2015 is in the names, not in the ids. I feel i'm much closer now but something is still missing ....
Here is cleaned up version of what you are trying to do:
routes.rb
resources :workcategories do
get :drawings, to: 'drawings#workcategory_drawings'
end
resources :drawings
This gives you:
/workcategories/:workcategory_id/drawings => drawings#workcategory_drawings
drawings_controller.rb
..
def workcategory_drawings
#drawings = Drawing.where(workcategory_id: params[:workcategory_id]).all
end
..
(no need for before_action :list)
The dropdown (assuming that you have initialized #workcategories somewhere)
<% #workcategories.each do |workcategory| %>
<li>
<%= link_to workcategory.name, workcategory_drawings_path(workcategory) %>
</li>
<% end %>
Ok, so I have a notifications controller similar to SO's. It shows up fine when I'm in the nofications#index page but doesn't show on any other view such as my home page.
Is there any way for me to render the notifications partial while still including it's controller gobally (have it show on any & every page)?
Thanks in advance
here's my notifications controller
class NotificationsController < ApplicationController
def index
#notifications = Notification.where('user_id = ?', current_user.id)
end
end
Create a before_filter in ApplicationController that grabs whatever notifications you want the user to see and puts them into say #notifications. Then in your layout render the partial that displays them if #notifications has something in it.
class ApplicationController
before_filter :load_notifications
def load_notifications
#notifications = Notification.where('user_id = ?', current_user.id)
end
end
Then in say app/views/layouts/application.html.erb:
<% #notifications.each do |n| %>
<%= n.message %>
<% end %>