Use only a single controller in rails app - ruby-on-rails

I'm trying to develop an app where I only want one controller, and use anything in the url as an argument to that controller.
I've read that normally the url is parsed as GET controller/action, as in example.com/controller/action/params, but I would like to use a specific controller and a specific action.
Is there any way essentially to parse a url as example.com/params, always handled by the same action and controller?

There are a couple of examples of this in the Rails guide on routing. The file config/routes.rb is where you set up the mapping from URL's to controllers.
One specific example is this:
match '/:username' => 'users#show'
Any request that doesn't match further up will get routed to the UsersController's show method, with the string passed in the params hash as the value of the username key.

Yes, there is. In your config/routes.rb file define the route:
match "catchall/*page", :to => "catchall#respond"
Then in your controller:
class CatchallController < ApplicationController
def respond
end
end

I think this is bad idea, but you can do this, using render action:
def index
if self.class.instance_methods(false).include? params[:page].to_sym
render action: params[:page]
else
#error_404
end
end

Related

Getting param from friendly url like http://localhost:3000/user/adem-balka with Rails 5

So I want to display posts for an user in his/her profile page as at top user details, below all the posts.
I know I can get param from a url like http://localhost:3000/posts?category=article
with
if params[:category]
#category_id = Category.find_by(title: params[:category]).id
#posts = Post.where(category_id: #category_id)
end
but param doesn't work when I have an url like http://localhost:3000/user/adem-balka
So, how can I get user name to find its id and pull posts with that user id?
Thank you all.
The name of a parameter in a url is set in your routes file.
If you look at your routes in config/routes.rb, you should be able to find the line(s) that corresponds to the user model. It should look something like this:
get '/users/:name', to: 'users#show'
This means that if you go to /users/adem-balka, params[:name] will be set to 'adem-balka'. You can then access the parameter in the corresponding controller function.
What you are looking for is a path parameter, where adem-balka is say params[:username].
Assuming you have no forward slashes or dots in your parameter, this is as simple as adding /:username as part of your route, e.g.
get '/users/:username', to: 'users#show'
# in the controller
#user = User.find_by(username: params[:username])
This is all covered in the Rails Routing from the Outside In guide.
Note that the routes generated resources already contain the :id path parameter for you (for show, edit, etc.). But even if you change the controller, the generated helpers (e.g. users_path(#user)) will use the id.
To make it work with resources using say username instead of id however (e.g. users_path(#user) giving /users/ben instead of /users/5), you need to also override the to_param method, e.g.
class User < ApplicationRecord
def to_param
username #rather than id
end
end
# routes.rb
get '/users/:username' => 'users#posts'
# users_controller.rb
def posts
username = params[:username]
# etc..
end
This is described in the Rails Docs as Routing Parameters.
thank you for the answers. I learned from them 🙏
and this solved my problem
#user_id = User.friendly.find(params[:id])
#posts = Post.where(user_id: #user_id)

Passing params using redirect to different action in controller

This is first action in controller:
def investor_following
#investor = params[:user][:investor_id]
# blah
end
def change_amount
investor = "xyz"
redirect to :action => :investor_following, :user[:investor_id] => investor
end
I am getting error how can I redirect to action investor following, what would be right syntax to do with params.
You should create a named route for your action in your routes.rb. I'm not sure what you investor_following function will do, so I am not certain if it should be a GET, POST, or PATCH. If you intend to modify your model, use a POST/PATCH, if not, use a get.
Once you have a named route, you will get a path helper like investor_following_path which you can send parameters as ruby objects:
#routes.rb
get '/investor_following', to: 'controllername#investor_following', as: 'investor_following'
#in your controller
redirect_to investor_following_path(user: {investor_id: investor})
This is untested but in general what you should do.
Here is info on redirect_to:
http://api.rubyonrails.org/classes/ActionController/Redirecting.html
Here is the info on routing for your named path:
http://guides.rubyonrails.org/routing.html

Rails help creating redirecting action and route

I am trying to create a route and a action that redirects the params.
Example when a user visits: www.mywebsite.com/photographer/flv/:ID/:filename
I want the user to be redirected to: www.someotherwebsite.com/photographer/flv/:ID/:filename
I have tried to accomplish with this solution without luck:
My controller URL:
def videore
redirect_to www.whateverwebsite.com + params[:all]
end
And in routes:
match '/photographer/flv/:ID/:filename' => 'URL#videore'
This should do it:
In your controller action:
def videore
redirect_to "http://www.whateverwebsite.com/photographer/flv/#{params[:id]}/#{params[:filename]}"
end
And in routes:
match '/photographer/flv/:id/:filename' => 'url#videore'
This assumes, of course, that 'url' is the name of your controller
From the Ruby on Rails Guide:
match "/stories/:name" => redirect("/posts/%{name}")
In all of these cases, if you don’t provide the leading host
(http://www.example.com), Rails will take those details from the
current request.
So redirecting to another TLD should work like this (no action in your controller required):
match '/photographer/flv/:ID/:filename' => redirect("http://www.someotherwebsite.com/photographer/flv/%{ID}/%{filename}")

Rails redirect_to post method?

redirect_to :controller=>'groups',:action=>'invite'
but I got error because redirect_to send GET method I want to change this method to 'POST' there is no :method option in redirect_to what will I do ? Can I do this without redirect_to.
Edit:
I have this in groups/invite.html.erb
<%= link_to "Send invite", group_members_path(:group_member=>{:user_id=>friendship.friend.id, :group_id=>#group.id,:sender_id=>current_user.id,:status=>"requested"}), :method => :post %>
This link call create action in group_members controller,and after create action performed I want to show groups/invite.html.erb with group_id(I mean after click 'send invite' group_members will be created and then the current page will be shown) like this:
redirect_to :controller=>'groups',:action=>'invite',:group_id=>#group_member.group_id
After redirect_to request this with GET method, it calls show action in group and take invite as id and give this error
Couldn't find Group with ID=invite
My invite action in group
def invite
#friendships = current_user.friendships.find(:all,:conditions=>"status='accepted'")
#requested_friendships=current_user.requested_friendships.find(:all,:conditions=>"status='accepted'")
#group=Group.find(params[:group_id])
end
The solution is I have to redirect this with POST method but I couldn't find a way.
Ugly solution: I solved this problem which I don't prefer. I still wait if you have solution in fair way.
My solution is add route for invite to get rid of 'Couldn't find Group with ID=invite' error.
in routes.rb
map.connect "/invite",:controller=>'groups',:action=>'invite'
in create action
redirect_to "/invite?group_id=#{#group_member.group_id}"
I call this solution in may language 'amele yontemi' in english 'manual worker method' (I think).
The answer is that you cannot do a POST using a redirect_to.
This is because what redirect_to does is just send an HTTP 30x redirect header to the browser which in turn GETs the destination URL, and browsers do only GETs on redirects
It sounds like you are getting tripped up by how Rails routing works. This code:
redirect_to :controller=>'groups',:action=>'invite',:group_id=>#group_member.group_id
creates a URL that looks something like /groups/invite?group_id=1.
Without the mapping in your routes.rb, the Rails router maps this to the show action, not invite. The invite part of the URL is mapped to params[:id] and when it tries to find that record in the database, it fails and you get the message you found.
If you are using RESTful routes, you already have a map.resources line that looks like this:
map.resources :groups
You need to add a custom action for invite:
map.resources :groups, :member => { :invite => :get }
Then change your reference to params[:group_id] in the #invite method to use just params[:id].
I found a semi-workaround that I needed to make this happen in Rails 3. I made a route that would call the method in that controller that requires a post call. A line in "route.rb", such as:
match '/create', :to => "content#create"
It's probably ugly but desperate times call for desperate measures. Just thought I'd share.
The idea is to make a 'redirect' while under the hood you generate a form with method :post.
I was facing the same problem and extracted the solution into the gem repost, so it is doing all that work for you, so no need to create a separate view with the form, just use the provided by gem function redirect_post() on your controller.
class MyController < ActionController::Base
...
def some_action
redirect_post('url', params: {}, options: {})
end
...
end
Should be available on rubygems.

Is it possible to change the default action for a RESTful resource?

In Ruby on Rails, is it possible to change a default action for a RESTful resource, so than when someone, for example, goes to /books it gets :new instead of the listing (I don't care if that means not being able to show the listing anymore)?
I'd point out that if you are pointing /books to /books/new, you are going to be confusing anyone who is expecting REST. If you aren't working alone, or if you are and have other come on board later, or if you expect to expose an API to the outside, the REST convention is that /books takes you to a listing, /books/new is where you create a new record.
Not sure why would you do such a thing, but just add this
map.connect "/books", :controller => "books", :action => "new", :conditions => { :method => :get}
to your config/routes.rb before the
map.resources :books
and it should work.
Yes. You should be able to replace your index method in your controller...
def index
#resource = Resource.new
# have your index template with they proper form
end
In the same vein, you can just do
def index
show
end
def index
redirect_to new_book_path
end
I think would be the simplest way.

Resources