My link and route is not working in rails - ruby-on-rails

My problems started right out of the gates, lol.
Basically, my button linked to a signup form is not going anywhere and just keeps coming back to my home page where I started.
Here is my home page where the sign up button is.
<!DOCTYPE html>
<html>
<head>
<title>Flight Scheduler</title>
</head>
<body>
<nav>
</nav>
<h1>Welcome to the Flight Scheduler</h1>
<%= button_to "Login", '/login', method: :get%>
<%= button_to "Sign Up", '/users/new', method: :get %>
</body>
</html>
Here is my route for it.
root 'static#home'
#users
get '/users/new', to: 'users#new', as: 'new_user'
Lastly here is my controller
class UsersController < ApplicationController
def index
#users = User.all
end
def new
#user = User.new
end
def create
#user = User.create(user_params)
session[:user_id] = #user.id
redirect_to '/welcome'
end
private
def user_params
params.require(:user).permit(:name,:password,:admin)
end
end
When I click the sign-up button it doesn't leave the home page. When modified it earlier, it gives me a error that no route matchs [GET] '/users/new', but when I did my rake routes command it is there. How can I get over this hump?

You can try to replace the helper button_to to link_to.
<%= link_to "Login", '/login' %>
<%= link_to "Sign Up", '/users/new' %>

As said by Vinícius Alonso, you should use link_to instead of button_to. I am guessing that maybe when you click that button you are making an ajax, and RoR is making that request with format .js and with data-remote = true. That means your server are sending a empty body to your front, and instead changing a location are handling that petition by javascript. So, thats why is not changing. With link_to, RoR generates an anchor, and all your troubles will be solved.
If you are using button_to, to making any other behaivor, you just add local= true to button_to helper!
Good luck!

Related

Ruby on Rails Custom Controller Action for Users Controller

Working on versions:
Ruby: 3.0.2
Rails 6.1.4
I'm trying to put a button in my View template for "Users" that will set the :mod attribute to false, with the button just being "Demote User".
I had it working SOMEHOW using a helper method, demote_user, and some variation of
<% if logged_in? && current_user.admin? %>
<%= link_to "Demote User", user_path(#user), onclick: demote_user(#user), class: "btn btn-info" %>
<% end %>
I messed up however it was working when trying to move this method into a controller for best practice. I'm not sure what format worked out, but I've tried many such as
:onclick => demote_user(#user)
onclick: 'demote_user(#user)'
onclick=demote_user(#user)
onclick='demote_user(#user)
and etc. Somehow, it did eventually work but I busted it. Now, every time I load the User's page, it's just executing demote_user(#user) without even needing to click the button, so refreshing a User's page is demoting them.
I am now trying to do this properly by creating a demote method in the UserController, but I have NO IDEA how to make the route, or make it work properly. Up until now, all my routes have been working using resources, and the basic new, create, destroy, etc.
I've been trying many different routes, and view formatting, with no luck and usually ending up with just: Routing Error
No route matches [GET] "/demote.3"
I'd like to be able to avoid using the Javascript onClick functionality and do it properly with the controller even if I could remember how to make it work, but I think my route, or view page, or controller is incorrect. Here are the contents of each file:
Controller
def demote
byebug
#user = User.find(params[:id])
#user.mod = false
redirect_to user_path(#user)
end
View
div class="container text-center mt-4">
<% if logged_in? && current_user.admin? %>
<%= link_to "Demote User", demote_path(#user), class: "btn btn-info" %>
<% end %>
</div>
Routes
Rails.application.routes.draw do
root 'pages#home'
get 'about', to: 'pages#about'
resources :articles
get 'signup', to: 'users#new'
resources :users, except: [:new]
get 'login', to: 'sessions#new'
post 'login', to: 'sessions#create'
delete 'logout', to: 'sessions#destroy'
resources :categories
post 'demote', to: 'users#demote'
end
Up until now, I've been following a course, and I've nailed everything in it and have added some of my own functionality, but I'm still not quite sure how to make sense of routes, or what paths it creates.
I'd like to make other similar custom controller functions beyond show, index, create, delete, update which are all I really understand how to build. I'm not even sure if POST is the correct call in the route.
I would just setup an additional RESTful action for the resource:
resources :users do
patch :demote
end
<% if logged_in? && current_user.admin? %>
<%= button_to "Demote User", demote_user_path(#user), method: :patch %>
<% end %>
You can use link_to instead of button_to but you need to use the correct method: :patch or data: { turbo_method: :patch } option depending on your version of Rails to get the javascript driver to do its trickery.

Can I run the #new and #create methods of my #game controller on my home page?

I am creating a counter for a card game and would like to have a "New Game" button directly on my homepage, meaning without passing on the #new-game view.
My #game model doesn't need any information to be created (e.g: name...) so no form on a #new-game view needed to create it. The app is currently working but I have to pass on my #new-game view before a #game can be created.
I am struggling with the logic of the #new and #create actions of my #game controller taking place on my #home view (#pages controller).
Can anybody help ?
Thanks a lot
Here's my #game controller :
def new
#game = Game.new
#game.biddings.build
end
def create
#game = Game.new(game_params)
#game.save
redirect_to game_path(#game)
end
My #page controller :
class PagesController < ApplicationController
skip_before_action :authenticate_user!, only: [:home]
def home
end
end
And my #home view :
<div class="full-height home-colors">
<div class="abs-center">
<h1>BIENVENU SUR COINCH'COUNT !</h1>
<p>Coinch'Count est un compteur de points simplifié pour la coinche.</p>
<%= link_to 'Nouvelle partie', new_game_path, class: 'regular-btn' %>
<%= link_to 'Liste de toute les parties', games_path, class: 'transp-btn' %>
</div>
</div>
The idea being to have the first link_to directly creating a #game instance and redirecting to the #game show.
Can I run the #new and #create methods of my #game controller on my
home page?
No. Each request in Rails will only ever run one controller action so its a nonsensical goal.
What you really want to do is just add a form or a link on your pages/home.html.erb view that sends a POST request to /games.
You can do this with button_to which creates a form that just contains a single button:
# these all generate the exact same HTML
<%= button_to("Create game", Game.new) %>
<%= button_to("Create game", games_path, method: :post) %>
<%= button_to("Create game", controller: :games, action: :create) %>
This will work even if the client has turned JS off as its just a standard HTML form.
You can also use link_to with the method option:
# these all generate the exact same HTML
<%= link_to("Create game", Game.new, method: :post) %>
<%= link_to("Create game", games_path, method: :post) %>
<%= link_to("Create game", controller: :games, action: :create, method: :post) %>
This adds a data-method="POST" attribute to the link. Rails UJS defines a event handler for elements with this data attribute which will create a form and post it to the server so that a POST request is sent instead of GET.
If there are any JS errors that prevent the handler from working (like Rails UJS not being loaded) the default browser action of sending a GET request will happen instead so make sure you check the browser console if you run into problems.
You can try to declare your link as a "post", and use the creation path games_path :
<%= link_to 'Nouvelle partie', games_path, method: :post, class: 'regular-btn' %>
It will work because, as you said, you don't have any mandatory parameter:
My #game model doesn't need any information to be created

Devise destroy session doesn't destroy the session?

Really new to devise - it's very frustrating in all honesty...
My user session isn't being destroyed.
Here is the link in my navbar:
<li><%= link_to 'Logout', destroy_user_session_path, :method => :delete %></li>
devise.rb has the :delete method configured:
# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = :delete
Route is:
destroy_user_session DELETE /users/sign_out(.:format) sessions#destroy
Application controller says :
class ApplicationController < ActionController::Base
protect_from_forgery
private
def after_sign_out_path_for(resource_or_scope)
root_path
end
I click my sign out link and my console shows :
Started GET "/users/sign_out" for 127.0.0.1 at 2014-04-18 12:00:26 -0500
Processing by UsersController#show as HTML
Parameters: {"id"=>"sign_out"}
MONGODB (0.8ms) waittext_development['users'].find({:_id=>BSON::ObjectId('53515685963e6507ad00003e')}).limit(-1)
It doesn't seem to be finding an active session (I've clicked it a dozen times in frustration), but the problem is the page I land out - UsersController#show - is not the page I've told it to route to. It should be the root_path which is users#index
So I was getting all these nil class errors on users#show because it was trying to render the default rails #user.name, etc. and #user isn't defined - I finally manually overrode the show action to simply render 'index' and I end up on my index page - BUT STILL - I'm seeing current_user.email printed here:
<% if user_signed_in? -%>
<ul>
<li><%= current_user.email %></li>
<li><%= link_to 'My info', edit_user_registration_path %></li>
<li><%= link_to 'Sign out', destroy_user_session_path %></li>
</ul>
It is evaluating TRUE and I'm getting those three list items.
User should not be signed in because I just destroyed the session!
What the heck?
You issue a GET request, not a DELETE (or even a POST with a set _method parameter to emulate a proper DELETE). As such, your request is routed to UsersController#show which listens to GET /users/:id.
The reason for that is, that a plain HTML link normally can only lead to GET requests. For anything else, you need a form. If you now pass the :method parameter to the link_to method in your view, Rails will generate some Javascript which captures the click on the link to generate a form and send the request that way. This will fail if the user has Javascript disabled, which seems to be the case here.
You should thus either ensure that all users (including you) have Javascript enabled or use something like button_to instead which will create a proper form in HTML which works without Javascript.
This is how i have implemented this so known to work:
devise_scope :user do
match "sign_out", :to => "sessions#destroy", via: [:delete]
end
<%= link_to sign_out_path, :method => "DELETE" do %>
<% end%>

Adding dynamic login and logout links rails 3.1

I have a very basic sign up and log in setup running and all I want to know if how to add a link at the very top of my root page that displays 'Log in' or 'Sign out' depending on whether the user is logged in or not.
I have tried various methods I have found on here but can't seem to get them to work as they often create undefined method errors.
What is the simplest way to create this?
Many thanks in advance for your help.
Tom
if you have a session variable where you save the id of the current user (i call it user_id) you could do it like this:
<% if session[:user_id] %>
<!-- user is logged in -->
<%= link_to logout_path %>
<% else %>
<!-- user is not logged in -->
<%= link_to login_path %>
<% end %>
that is what you have to change:
config/routes.rb:
resources :users
# login stuff
controller :sessions do
get "login" => "sessions#new"
post "login" => "sessions#create"
delete "logout" => "sessions#destroy"
end
app/views/sessions/new.html.erb:
# replace this line
<%= form_tag new_session_path do %>
# with
<%= form_tag login_path do %>
the login link is now:
<%= link_to "Login", login_path %>
the logout link:
<%= link_to "Logout", logout_path, :method => :delete %>
Not much of an answer but this Railscast was very helpful to me in learning about how authentication works in rails. The Railscast is Twitter login specific using OmniAuth but the process is much the same. He includes the dynamic links you asked about in his code.
http://railscasts.com/episodes/241-simple-omniauth

Youtube embed link not displaying in Rails

I'm making resourceful routes for youtube videos. So, a person just pastes the youtube embed link in the form. In the controller I have a normal set of resourceful actions:
class VideosController < ApplicationController
def index
#videos = Video.all
end
def new
#video = Video.new
end
def create
Video.create(params[:video])
redirect_to :action => :index
end
def destroy
Video.destroy(params[:id])
redirect_to :action => :index
end
end
And in the view I'm just displaying it: (in Haml)
- #page_title = 'Video'
#videos
%ul
= list_of(#videos) do |video|
%h1= video.title
!= video.link
= link_to "Delete", video_path(video), :method => :delete
= link_to "Add new video", new_video_path
%p#top
= link_to 'Go to top ↑', '#'
For the one who don't use Haml, != escapes the string. video.link holds the YouTube embed code
The problem is that, when I create a new video, and when it redirects me back to the index page, the newly created video isn't displayed (the other ones are normally displayed). Only after I refresh the page, it's normally displayed.
I saw in the web inspector that the src attribute is missing from the iframe (so that's why the video isn't displayed). But when I look in the page source, everything is normal there. So, thinking it may be Javascript's fault, I tried disabling it. But nothing changed.
I don't think you want to escape it using haml... I think you want to call
video.link.html_safe
Note: if the user is pasting in the link, this is very unsafe.
Update --- If you have the javascript develop console open, you'll see this error pop up:
**Refused to execute a JavaScript script. Source code of script found within request.**
Check this answer for why it's refusing to due XSS Here's a method that is both safe and works. You'll paste in the youtube ID in the text field: ibWYROwadYs
index.erb
<% if session[:youtube].present? %>
<iframe width="480" height="360" src="http://www.youtube.com/embed/<%=session[:youtube]%>" frameborder="0" allowfullscreen></iframe>
<% end %>
<%= form_tag load_path do %>
<%= text_field_tag :youtube_id %>
<%= submit_tag "Submit" %>
<% end %>
<%= link_to "Clear", clear_path, :method => :delete %>
home_controller.rb
class HomeController < ApplicationController
def index
end
def smth
session[:youtube] = params[:youtube_id]
redirect_to :action => :index
end
def clear
session.clear
redirect_to :action => :index
end
end

Resources