Rails route error: NoMethodError - ruby-on-rails

I'm new to Rails, and am trying to create a page that is largely a copy of my users#show page, with slightly different content and formatting. Ideally, this would work something like this:
Normal route: http://myUrl.com/users/2
New route: http://myUrl.com/users/2/lightbox <-this is the new route with the formatting. It should have access to user #2's info.
I did some research on stack overflow, and added the following to routes.rb
resources :users do
member do
get 'lightbox'
end
end
and then raked the routes. This allows me to type in the url http://myUrl.com/users/2/lightbox . However, it doesn't seem to have access to any of the user class's resources, and seems to have no idea who User #2 is.
I may completely have gone about this the wrong way - all I really want to do is create a custom page to display an individual user's information that's different from the show page. I'd really appreciate any help!

You need to add an action to your app/controllers/users_controller.rb:
def lightbox
#user = User.find(params[:id]
# any other logic, look at your show method
end
Routing only maps a url to a controller action. It is up to the controller action, each individually, to set variables and render the view.
Before filters and helper methods are used make sure you don't have to write code a bunch of times. For example:
before_filter :find_user, only: [ :show, :lightbox ]
def show
end
def lightbox
end
protected
def find_user
#user = User.find(params.fetch :id)
end

Related

Using devise for user registration/login redirect user to a different form page based on their response

I am using devise for user registration/login, after the user has successfully signed up, I want to show a page/a dialog box and redirect to another page based on user response. How can I do that?
User Model (By devise)
username
password
Student Model
name
student_id
Teacher Model
name
grade
First_page:
signup signin links
Signup link will show the devise views/devise/registrations/new.html.erb page.
After successful signup, it takes the user to root page. I have defined the root page in routes.rb:
` Rails.application.routes.draw do
devise_for :users
resources :students, :teachers
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root to: "students#index"
end `
At this point, the application doesn't have any idea who the user is.
So, I want to get the identity information(student/teacher) from the user.
How will I get this information?
Student/Teacher controller:
`class StudentsController < ApplicationController
before_action :authenticate_user!, only: [:new, :create]
def index
#students = Student.all
end
def new
#student = Student.new
end
def create
current_user.create_student(student_params)
redirect_to root_path
end
private
def student_params
params.require(:student).permit(:name, :skypid)
end
end`
After the user has successfully signed in, I want to ask if the user is a student or teacher. Based on what they select, redirect them to a student form page or teacher form page.
How can I do that in rails?
Thank you
You can write a custom after_sign_in_path_for function in your ApplicationController assuming you're using all the default Devise controllers otherwise. Any named path helper or other route that it returns will be where the user is redirected, so you could do something simple like always redirect to a selection page that presents the options and handles the choice on a subsequent action:
def after_sign_in_path_for(resource)
user_type_selection_path # whatever route in your app manages the selection
end
Alternately, you could invoke a custom method on the user model in that function to make a choice right there:
def after_sign_in_path_for(resource)
resource.student? ? student_path : teacher_path
end
You could hybridize these of course as well to do the latter when the selection has already been made and redirect otherwise, with something similar to the following:
def after_sign_in_path_for(resource)
if resource.user_type_chosen?
resource.student? ? student_path : teacher_path
else
user_type_selection_path
end
Bear in mind that none of those functions or paths are real, since I can't be more specific on the information you've provided, but hopefully this gets you headed in the right direction. The after_sign_in_path_for hook is your primary tool here, unless you get into the world of overriding the default devise controllers and interrupting the usual workflow there to accommodate this step, which doesn't seem strictly necessary by your description.

New page not loading - ActiveRecord::RecordNotFound

This strikes me as pretty simple, which is why it's bugging me that I can't figure it out. I am creating a basic news app in rails. I have a "Posts" controller that controls the content for my basic pages. I want to have a page with local news. I went into the posts controller and made a new action called "local"
def local
end
I then went into my routes.rb file and made a route for the page.
get "posts/local" => "posts#local"
I then created a local.html.erb file and placed it in my post views.
When I try to click a link with the posts_local_path, I get this:
ActiveRecord::RecordNotFound
Extracted source (around line #74):
72
73
74
75
76
77
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.friendly.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
I don't understand. This is not involved in any way with the page I am trying to open. I'm not using that part of the controller. I'm stuck. Can someone help me understand what I'm doing wrong? Thank you!
I'm assuming you have before_action in your controller
You want to ensure that's not called for the local action
before_action :set_post, except: [:local]
or if it's only used in show
before_action :set_post, only: [:show]
You can pass either except or only arrays of the action names as symbols.
The problem originates from the fact that you're not passing any id in the params to the controller. Hence your method set_post cannot retrieve any post and returns the ActiveRecord error.
So you've got 2 options:
Either you want to use set_post and need to specify an :id param in your routes
Or you avoid calling set_post by adapting your before_action filter (as per the answer of j-dexx)

RESTful account selection controller in Rails?

In my app, after a user logs in, he is redirected to the AccountsSelection controller. In there, I have an index action that basically will get all the potential accounts a user can use, and display them in a index view.
def index
#accounts = current_user.eligible_accounts
end
In that page the user can click in one of the accounts, and that should go to one of the actions in the controller, that will set this in the session:
def show
session[:selected_account] = params[:account_id]
redirect_to account_path
end
Right now I have made that action to be show (so the selection of the account is doing a GET request, but I am not sure if this is a RESTful way of approaching this). From my point of view this is not a PUT/POST because I am not changing any resource or creating any resource, but it seems weird to be using the show action to just set a session.
What would be a proper way of handling this? It is correct to use show?
It is not recommended to use session in this case. So the standard approach is to create a before_action to set the account_id.
Use like this:
before_action :set_account, only: [:show]
and create the function in private as:
private
def set_account
account_id = params[:account_id]
end
Hope this helps.

How to route url - Ruby

I'm creating a new webpage were my users can have profile pages, and I can't seem to find the way to make a url like this:
webpage.com/profile/username
To go to my profile_controller action index and use the variable that comes on /username.
But I can't seem to find the way.
profile_controller.rb
class ProfileController < ApplicationController
def index
profile_info = Profile.find(params[:username])
end
end
And I've tried to work it around with the routes.rb but couldn't make it...
This route in your routes.rb should map get requests on /profiles/username to the index action of your profiles controller and pass the username value in params[:username]
get '/profiles/:username' => 'profiles#index'

Correcting invalid Resource Routes in Rails

One thing I noticed when working with nested resource routes in Rails is that it is technically possible for a user to visit a route where the child resource exists (and is therefore displayed correctly), but the id for the parent resource represents an object that is not actually related to the child resource.
For example, in the route users/:user_id/post/:id, the user could type in a route where :user_id represents a user who did not make the post corresponding to :id.
What would be the best way to fix this so that if the user visits an invalid URL, the server redirects the user to the correct URL?
I have already put some code in my controllers to handle this, but it's kind of awkward having to check the path in every controller action and then redirect the user to the appropriate url, especially since the URL helpers are different for every action.
(edit_user_post_path(#user, #post), new_user_post_path(#user, #post))
There has to be a better way, right?
You should have a before_filter running on all requests that makes sure the user is valid. If not, it will throw ActiveRecord::RecordNotFound and show the friendly 404 page.
Then grab the post based on the user however you need, whether in another before_filter or directly in the action. Base your post search on the user. My example below demonstrates doing this with another before_filter.
before_filter :find_user_by_user_id
before_filter :find_post
def show
# Use #post variable here however you need
end
private
def find_user_by_user_id
#user = User.find(params[:user_id])
end
def find_post
# This assumes you have an association set up as needed
#post = #user.posts.where(id: params[:id]).first
if #post.nil?
# Do whatever you need here
end
end
First of all you should know that the error wich is raised by ROR will display the message 'Sorry but the page you are looking for does not exist' on a production environment.
Therefor I would not be concerned about that. if you want to 'capture' the failure and quickly redirect to a safe area you might be interested in using the rescue method.
http://www.simonecarletti.com/blog/2009/12/inside-ruby-on-rails-rescuable-and-rescue_from/
have fun

Resources