Adding NEW controller to a Ruby on Rails 4 Spree -Ecommerce application - ruby-on-rails

I am trying to add a new controller a Ruby on Rails 4 Spree -Ecommerce application. First of all, in routes.rb I added root :to => 'login#login' then in app/controllers/ I added a file called login_controller.rb and in the file I added the following code.
module Spree
class LoginController < Spree::StoreController
def login
render('spree/shared/_login')
end
end
end
When I start the server and go to localhost:3000/ I get this error
Unable to autoload constant LoginController, expected superclass mismatch for class LoginController
My goal here, is to require login to even view the home page of the store. I am attempting to build a site where users get a login screen when the go to it unless they are already logged in.
Please know that I am ruby noob and this is actually my first ruby on rails application so I am completely clueless here.
Also if there is a better way to go about doing what I want (requiring a login to basically view any page on the site) than my current apporach (having a LoginController which checks if there is a user logged in - if so redirect to home, if not redirect to Login) please let me know.
P.S. I got the layout for the controller from the home_controller.rb in the spree gem

I have not tested the code, but I suggest you use Spree's Devise integration
then you can add a before filter mandating authentication. Create a decorator to contain this logic addition. Create a file called base_controller_decorator.rb inside app/controllers/spree with the following code:
Spree::BaseController.class_eval do
before_filter :check_logged_in
def check_logged_in
unless spree_current_user
redirect_to spree_login_path
end
end
end

I guess if you are in the Spree module you don't need the namespace for the superclass class LoginController < Spree::StoreController like so class LoginController < StoreController.

Related

How to run class method via URL in Rails 4

I'm real beginner in Rails.
I created app/services/xclass.rb class with some_method inside.
I need to execute some_method using url.
For example, I want run this method when I execute in my browser url - http://application.com/notifications/send
I think it could be done through controller (notifications_controller) but how to do it?
I created only controller, with no model, just for launching some_method.
first, create a route:
get "notifications/send" => "notifications#some_action", :as => "send_notification"
Then create a controller action in your controller (ie. NotificationsController):
def some_action
Xclass.some_method # run the method you want
redirect_to root_path # redirect or whatever you want here
end
Now you can either visit the path http://your_app.com/notifications/send, or link to is using 'send_notifications_path' url helper in rails.
That should do it
Since you're a beginner, let me give you some ideas
MVC
Firstly, you need to appreciate that Rails is an MVC (model view controller) framework:
In short, this means that every time you send a "request" to Rails, it will be "routed" to the specific controller action which corresponds with that route.
This means that when you ask about how to fire a "class method", you're going to have to work within the confines of the MVC programming pattern. Here's how:
#config/routes.rb
resources :notifications do
get :send, on: :collection #=> domain.com/notifications/send
end
#app/controllers/notifications_controller.rb
class NotificationsController < ApplicationController
def send
#call your class method here
YourModel.class_method
end
end
#app/lib/your_model.rb
class YourModel
def self.class_method
#do something here
end
end
--
Rails
This is further supported by the fact that Rails is just a framework - in fact it's a gem (a great one) which runs on top of Ruby.
This means that even though some of the ways in which Rails works might seem somewhat alien to begin with, you have to remember that it basically just captures "requests" fed to it by a web sever, processing them with connectivity to the database etc.
The issue here is that as you're sending the request over HTTP, you have to work within the constraints of this protocol (specifically that it's stateless), and with Rails. As mentioned, Rails is MVC-based, which means that every request will be routed to your controller, which is why you have to create the corresponding route & controller action to handle it
If you use the code above (tweaked to your app), it should work for you

Where can I find devise controller?

I'm trying to apply this post ( Devise update user without password ) for users don't need to insert password to update informations.
But, I'm very confused where is this controller. Devise don't create any controller in my app/controller folder. I search in all the folders but I cant find.
Where I that controller?
I see posts talking about create a new controller, but I just want to modify little things.
You don't edit (or shouldn't) the Devise controllers. Instead you create your own controller and inherent from the Devise controller.
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
super
end
def update
# add custom update logic here
end
end
Notice how RegistrationsController inherets from Devise::RegistrationsController. Now you can overide the registration methods (or modify them and call super). Even the page you are referencing about overriding the devise default behavior relies on class inheritance.
JTG offers good advice, you shouldn't edit the gem directly. As a more direct answer to the question:
To print the folder of your gem:
$ bundle show devise
To open the gem in a text editor ( while being sure not to change anything )
$ bundle open devise

User scope with Devise and Rails 4.1

I'm doing some proof of concepts with Rails. I created a Customer, and apply to it DEVISE.
Everythig works fine, but now i'm trying to logging with a customer and enter directly into his scope.
localhost:3000/customers/1
After this hide the /customers/1 with some word, for example: myProfile.
I'm trying to do the first part with
module ApplicationHelper
protected
def after_sign_in_path_for(resource)
#path to redirect
end
end
I was trying with definitions from routes.rb
redirect_to(customers_path)
or something like:
#customer= Customer.find_by_email(current_customer.email)
redirect_to(customer_path(#customer))
But nothing is working yet.
I'm not sure how to send messages to the console of the server (like in Java with some System.out.println) to check the contents...
Thanks a lot!

Alias route's name

I need to have one path accessible through multiple names. In my routes.rb I did
get '/route' => 'controller#edit', :as => 'name_a'
get '/route' => 'controller#edit', :as => 'name_b'
This works nicely but loads the routes table for nothing. From my understanding of the documentation, :as defines a helper method when called.
So I went to my ApplicationController and added
alias_method :name_b, :name_a
and I removed the second line from routes.rb
but that fails with Uncaught exception: undefined method name_a for class ApplicationController
is there any proper way of having two names for a single path?
=================EDIT====================
Elaboration:
I use Devise gem to manage session, registration, locking, etc. of 2 kinds of users, let's call them Admin and Guest. The gem is very well put but it asks for definitive route names to behave properly.
In my case, as far as devise is concerned, only the registration process is different so I'm trying to build a structure which looks as follow:
app
controllers
users
admin
registration_controller.rb
guest
registration_controller.rb
session_controller.rb
password_controller.rb
registration_controller.rb
the Admin and Guest controllers inherit from the above registration_controller which inherit's from Devise.
Now, to work properly, Devise needs for instance the names guest_user_password and admin_user_password to create or delete password retrievals. In my case, both are under the same path so I want both names to redirect to the same 'users/password' controller.
More important, and that's why I really wanted the alaising. Is that my views should not care whether it is dealing with Admin and Guest routes when redirecting to password retrieval controller. Both are users so I want to use user_password for both.
Hence my question. :)
Also note that as I wrote it, things works. I'm just trying to get the 'most elegant way' of writing it.
How about putting the alias in your ApplicationController?
class ApplicationController < ActionController::Base
alias_method :route_new, :route_old
helper_method :route_new
Remember that it's new name first, then old name.
The helper_method call is in order to use these in your views and not just controllers.
If you like, you can then place this in an included module called something like RouteAliases
You can add something like this to your routes.rb:
Rails.application.routes.draw do
...
Rails.application.routes.named_routes.tap do |named_routes|
named_routes['new_name'] = named_routes['real_name']
end
end
This will create new_name_path and new_name_url helpers. I have tested this with Rails 5.0.6.

Ruby on Rails' gem "Devise" doesn't even have a controller file in app/controllers?

After installing Devise, there are routes to
/users/sign_in
/users/sign_up
/users/sign_out
but there is no file app/controllers/users_controller.rb? why does this require no controller file or is it just some where else?
The controller file is located within the gem, and you don't need to write one yourself. Most everything can be done via configuration. See https://github.com/plataformatec/devise#readme for more specific details.
You can, however, generate the views so that you may override them yourself:
rails generate devise:views
That will place files in app/views/devise that you can modify for all of the forms, etc. that Devise provides.
It's bundled with the gem. You can generate a controller 'User' separately with further actions:
class UserController < ApplicationController
def show
#user = current_user
end
end

Resources