rails, query via url - ruby-on-rails

I created my app using the following scaffold
rails generate scaffold server hostname:string
rails generate scaffold template remote_template_id:integer remote_template_name:string server:belongs_to
I edited the routes to be nested
resources :servers do
resources :templates
end
Now I edited stuff around and my app is working great. However, as this is back-end and not customer facing, I wish to able to run a query such as this, where 'templatename' at the end is an arbitrary string
http://127.0.0.1:3000/servers/1/templates/find_by_remote_template_name/templatename
Essentially, be able to search using the column name remote_template_name .
What would be the best way to approach this problem?

In your routes.rb file:
resources :servers do
resources :templates
match 'templates/search/:template_name', to: 'templates#search', via: :get
end
Then you should be able to query http://localhost:3000/servers/1/templates/search/whatever which will route to the #search action of the TemplatesController passing in params[:template_name]

Special Thanks to Jon.
Solution: the correct routing had to be set and the search function in the controller needed some tweaking
routes.rb:
resources :servers do
resources :templates
match 'templates/search/:template_name', to: 'templates#search', via: :get
end
And I had to add in the column name that is being searched in the TemplatesController
def search
#template = #server.templates.where("remote_template_name = ?", params[:template_name])
respond_to do |format |
format.html
format.json { render json: #template }
end
end

Related

Create views in resource in Rails

I am a beginner working with Rails: I have this routes.rb:
Rails.application.routes.draw do
resources :requirements
root "department#index"
get "department/about"
end
How can I create a view that has a path like requirements/major?
Thank you so much!
You can extend resources and add custom actions, like this:
resources :requirements do
collection do
get :major
end
end
You'll need an action in the RequirementsController that matches, e.g.
class RequirementsController < ApplicationController
def major
# set up whatever resource 'major' corresponds to
end
...
end
That's at least one way of doing it. You could also have a controller that directly supports the nested 'major' resource, which would be similar to above - just with a controller: 'name of controller' directive inline..
It'd probably pay to get your head around the "Rails Routing from the Outside In" guide: https://guides.rubyonrails.org/routing.html

How to setup Rails routes.rb for Vanity URL without requiring a prefix

I'm looking to setup routes.rb to support vanity URLs that do not require a prefix. For example not requiring the "articles/" in mysite.com/articles/seo-url-here. I want just mysite.com/seo-url-here
How can I setup routes.rb so that when a url hits my site: routes.rb looks to see if the value of seo-url-here in the url matches a record in my database in the table Article.seo_url. If not match is found, then routes.rb should move on down through the rest of the routes.rb file.
Basic code to get you started:
# config/routes.rb
Rails.application.routes.draw do
resources :posts
resources :authors
constraints(PostUrlConstrainer.new) do
get "/:id", to: "posts#show"
end
end
# app/constraints/post_url_constrainer.rb
class PostUrlConstrainer
def matches?(request)
title = request.path_parameters[:id]
Post.find_by(title: title)
end
end
# app/controllers/posts_controller.rb
def set_post
#post = Post.find_by(title: params[:id])
end
Related article: Pretty, short urls for every route in your Rails app - Arkency Blog
Searching for rails url constraint seems to help.

rails custom rest route with parameter

I have a questions controller and an associated model and a number of rest routes. Here is how it's set up in routes.rb:
resources :questions
I want to add a custom route that has the format /questions/widget/ID (where ID is the id of the question for which I want to generate a widget). I want this to be processed by the "widget" action in my questions controller. I've tried a number of things such as:
resources :questions do
member do
get 'widget/:id'
end
end
But nothing is working. I'm sure I'm missing something simple. Any ideas? Thanks in advance.
You do not have to specify the id since you are inside resources. It should look like:
resources :questions do
member do
get 'widget'
end
end
You can get more information from the Rails Guide. Look at section 2.9.1.
Edit: I just noticed that you are trying to match get /questions/widget/:id. This will set up a route for get /questions/:id/widget. This is more in line with Rails convention. If you really want it the other way, you need to set up a custom match statement:
match "/questions/widget/:id" => "questions#widget"
However, I would stick with convention.
I know it is old, but looking to fix another routing problem I ended here, it is possible, to do what you are asking for, here is an example
resources :articles do
get 'by_tag/:tag' => :by_tag, on: :collection
get 'by_author/:author' => :by_author, on: :collection
resources :comments, except: :show
end
now you have /artices/by_tag/:tag . The trick was to use on:collection.
Obviously don't forget to add the by_tag action and by_author.
class ArticlesController < ApplicationController
.....
def by_tag
...
end
end
Check this route works with
melardev#local~$ rails routes
Why don't you use this routes:
resources :questions do
resources :widgets
end
it will create path like questions/:question_id/widgets/new for you to create new widget for question with specific id of question.
This is what ended up working for me:
resources :post do
get "author/:author", to: "posts#author", on: :collection, as: "author"
end
Which outputs the following route:
author_posts GET /posts/author/:author(.:format) posts#author
Then in your controller, you need to create the author action:
class PostsController < ApplicationController
def author
#roles = Post.where(author: params[:author])
render :index # to reuse the index view
end
end
Then in your view:
<%= link_to post.author, author_posts_path(post.author), data: { turbo_frame: "_top" } %>

Render JSON instead of HTML as default?

I try to tell rails 3.2 that it should render JSON by default, and kick HTML completely like this:
respond_to :json
def index
#clients = Client.all
respond_with #clients
end
With this syntax, I have to add .json to the URL. How can I achieve it?
You can modify your routes.rb files to specify the default format
routes.rb
resources :clients, defaults: {format: :json}
This will modify the default response format for your entire clients_controller
This pattern works well if you want to use the same controller actions for both. Make a web version as usual, using :html as the default format. Then, tuck the api under a path and set :json as the default there.
Rails.application.routes.draw do
resources :products
scope "/api", defaults: {format: :json} do
resources :products
end
end
If you don't need RESTful responding in your index action then simply render your xml response directly:
def index
render json: Client.all
end
Extending Mark Swardstrom's answer, if your rails app is an API that always returns JSON responses, you could simply do
Rails.application.routes.draw do
scope '/', defaults: { format: :json } do
resources :products
end
end

Rails 3 Scaffolding, Adding Routes Question

rails 3 newbie, with a general question about adding an additional route after scaffolding.
I create a scaffold for books... Which works great, and provides a nice index page.
The Index page shows all books in the system,
I'd like to add a page '/books/yours' that shows the books the user created. I already added the user_id to the books table, so that's working when users create new books.
But I can't figure out how to add the 'yours' page... Here's what I did:
In the books_controller.rb added:
def yours
#books = Books.all
respond_to do |format|
format.html # yours.html.erb
format.xml { render :xml => #notes }
end
end
Then I added a views/books/yours.html.erb page with just an H1 tag that says bingo...
Then in routes.rb I added:
Cline::Application.routes.draw do
resources :books
devise_for :users
match '/books/yours', :to => 'books#yours'
root :to => 'pages#home'
But it doesn't work? What'd I do wrong? thxs!
you could do this:
resources :books do
collection do
get 'yours'
end
end
So the url looks like: /books/yours
Here's everything explained: http://edgeguides.rubyonrails.org/routing.html

Resources