How to access POST variables in Rails? - ruby-on-rails

I'm not really a Rails developer and I'm working on someone else's code.
Anyway, I'm trying to change the login function so that it uses POST instead of GET. Right now it looks like this:
def login
email = params[:email];
password = params[:password];
# login logic ...
end
What do I need to change to use POST variables instead?
EDIT: The line that looked relevant in routes.rb
match "service/login", :to => "service#login"
If there's something else I'm looking for, please let me know.

Change:
match "service/login", :to => "service#login"
to:
match "service/login", :to => "service#login", :via => :post
or (shorter):
post "service/login"

please try this:
match "service/login", :to => "service#login", :via => :post
and don't forget to use :method => :post in your login form :)

Related

how to make dynamic nested routes on rails?

I'll explain when open www.domain.com/:id should be check the :id is a page then use
get ':id' => 'pages#show'
else if :id is a Category use
get ':category' => 'categories#show'
sorry for my english
get ':page' => 'pages#show'
resources :categories, :path => '/' do
resources :posts, :path => '/'
end
constraints for routes is way to go, but I would suggest a bit different solution for your problem.
Consider creating custom Constraint objects, which will query the database in order to check if Post or Category exists:
app/lib/post_constraint.rb
class PostConstraint
def matches?(request)
Post.exists?(request[:id])
end
end
app/lib/category_constraint.rb
class CategoryConstraint
def matches?(request)
Category.exists?(request[:id])
end
end
In your app/config/routes.rb
get ":id" => "posts#show", constraints: PostConstraint.new
get ":id" => "categories#show", constraints: CategoryConstraint.new
You have to be aware of the fact, that id is very poor candidate for such comparison, because the Post is checked in first place, and if there is record matching, the "posts#show" will be accessed, and CategoryConstraint wot be even bothered.
For more, check the documentation.
You should consider adding a slug for both models to easier serve exactly what user expects to see. For this purpose, try gem friendly_id.
Hope that helps! Good luck!
why dont you write something like this:
routes.rb
get '/:category_id/:post_id', to: 'categories#post'
and in your categories_controller.rb
def post
#params[:category_id] and params[:post_id] will contain the params from the url
end
Couple of solutions
If your post id and category id follow a pattern you can add constraints to your routes
1)
get ':post_id' => 'posts#show', :constraints => { :id => /[A-Z]\d{5}/}
get ':category_id' => 'categories#show', :constraints => { :id => /[1-9]\d{5}/ }
2)
Add a custom method where both post_id/category_id routes point, in that check if the id is a post id or category id and based on that render the page

Devise logs users out after hitting certain routes

Here is my routes files:
Tubalr::Application.routes.draw do
devise_for :users
root :to => "application#index"
get "/player/:search_type/:search/:first_video" => "application#player"
get "/just/:artist_band.json" => "api#just"
get "/similar/:artist_band.json" => "api#similar"
get "/:username/favorites.json" => "api#userFavorites"
get "/just/:artist_band" => "application#index"
get "/similar/:artist_band" => "application#index"
get "/history" => "application#history"
get "/:username/favorites" => "favorites#init"
post "/check-favorites" => "favorites#check"
post "/favorites/add" => "favorites#add"
post "/favorites/remove" => "favorites#remove"
devise_scope :user do
get "/users/sign_out" => "devise/sessions#destroy"
end
end
The routes /history and the default /users/edit route for devise do not log the user out.
I'm not sure what other information to give, if theres something that would help debugging my problem, please let me know and I'll update the question.
The entire projects code can be found here: https://github.com/cjstewart88/Tubalr/tree/user_favorites
After digging around I finally ran into this:
https://github.com/plataformatec/devise/issues/913
It appears that the csrf token needs to be passed along with AJAX request, which my app is doing a good bit.

More Dynamic Routes?

I have this site where I want to be able to export all the data using CSV. There is a controller called "dataexport" and it has a method for each model. In my routes.rb file, I have this:
match "export_checkouts", :to => "dataexport/checkouts_csv"
match "export_committees", :to => "dataexport/committees_csv"
match "export_libitems", :to => "dataexport/libitems_csv"
match "export_locations", :to => "dataexport/locations_csv"
match "export_logs", :to => "dataexport/logs_csv"
match "export_patrons", :to => "dataexport/patrons_csv"
match "export_products", :to => "dataexport/products_csv"
match "export_questions", :to => "dataexport/questions_csv"
match "export_reasons", :to => "dataexport/reasons_csv"
match "export_roles", :to => "dataexport/roles_csv"
match "export_sales", :to => "dataexport/sales_csv"
match "export_shifts", :to => "dataexport/shifts_csv"
match "export_tasks", :to => "dataexport/tasks_csv"
match "export_tickets", :to => "dataexport/tickets_csv"
match "export_types", :to => "dataexport/types_csv"
match "export_users", :to => "dataexport/users_csv"
match "export_visitors", :to => "dataexport/visitors_csv"
match "export_years", :to => "dataexport/years_csv"
Is there a more dynamic way of doing this? This definitely goes against the "DRY" paradigm and was wondering if anyone could help me with this. I was thinking that you could just do this in one line by replacing the model names with a variable but I'm not quite sure how to go about doing this.
Why not just:
match "export/:model", :to => "dataexport/export_csv"
and use params[:model] to get the correct Model, then direct the dataexport controller export_csv method to ask the model for the data in CSV format like:
class DataexportController do
def export_csv
params[:model].constantize.export_csv
end
end
You could try this:
%w(checkouts committees).each do |model|
match "export_#{model}", :to => "dataexport/#{model}_csv"
end
Obviously fill out the array with all of the models you need this for.
However, whilst this cuts down on the code, you are still polluting your routes. You should consider that there might be a more Rails-way of doing this.
One thing Rails has support for is responding to different formats in controllers. So if a JSON format is requested by the browser, a JSON file is provided for by Rails (as long as you write the code for it). It sounds to me like you could just do the same thing with a CSV format.
What you are defining as "export" is really just the index method on a normal controller. It's just that rather than displaying the data as HTML, you are displaying it as CSV. I haven't really looked into this myself and so I'm not sure exactly how you would go about doing it. Something like this:
class FooController < ApplicationController
def index
respond_to do |format|
format.html #This will load your standard html index view
format.csv { #CSV stuff goes here. Perhaps you can get it to load app/views/foo/index.csv.erb somehow }
end
end
There is some discussion on this here: http://weblog.rubyonrails.org/2006/12/19/using-custom-mime-types

Rails route to username instead of id

I am trying to change the rails routes from /users/1 to /username. I currently set this up so it works for the actions of showing and editing. The actual issue is that when I go to update the user by using:
<%= form_for #user do |f|%>
It never updates, because the update action is routed to /users/:id. Is there any way to route this so that it works for /username? (which is the route that is rendering in my forms as the action). I've been scratching my head over this one for a while now.
EDIT:
The issue isn't routing to username, that it working correctly. The issue is that the form routes to /username for update, however the update route for users is still /users/:id instead of :/id.
I tried updating my routes to this, but to no avail:
match '/:id', :to => "users#show", :as => :user
match '/:id', :to => "users#update", :as => :user, :via => :put
match '/:id', :to => "users#destroy", :as => :user, :via => :delete
EDIT:
Doh! This fixed the issue:
match '/:id', :to => "users#show", :as => :user, :via => :get
In your user model:
def to_param
username
end
The to_param method on ActiveRecord objects uses, by default, just the ID of the object. By putting this code in your model, you're overwriting the ActiveRecord default, so when you link to a User, it will use the username for the parameter instead of id.
In the User model override the to_param method to return what you want used in the URL.
class User < ActiveRecord::Base
def to_param
username
end
end
In your controller instead of using User.find(params[:id]) you now need to use User.find_by_username(params[:id])
You can use friendly_id gem: https://github.com/norman/friendly_id
You don't have to override to_param if you don't want to, you can just specify in the form tag like this:
<%= form_for #user, :url => user_path(:id => #user.username) do |f|%>

(Rails 3) Is it possible to hardcode ids in a named route?

As far as I know, the following is the encouraged way to create a simple named route in Rails 3:
match 'sign-in' => 'sessions#create', :as => :sign_in
Is there a clean way to hardcode an id (or any parameter) in a named route? For a silly example:
match 'first-user' => 'users#show', :as => :first_user, :id => 1
Did you try that? It just works like that.

Resources