Ember Rails route URLS based on json ID - ruby-on-rails

This seems like it should be pretty simple but I can't seem to figure this out (bit new to Ember). I have a json file that I am using to load data into an ember template with handlebars. I am trying to have it so by visiting /site/id/ it would load data based on the id in the json file. Right now, it loads my json but only takes data from the first json entry. So no matter what /site/anythinghere/, that data is loaded. I am trying to make it dynamic.
I think my problem has to do with not having a model setup properly in ember. I've seen the docs and tutorials talk about the model: property and passing (params) and what not, but I can't seem to get anything to work in my site model or route.
Here's my code...
Router.js.coffee:
App.Router.map ->
#resource 'site', ->
#route 'show', path: '/:site_id'
Routes.rb:
#routes.rb
Rails.application.routes.draw do
root to: 'home#index'
scope constraints: { format: :html } do
get '/site' => 'home#index'
get '/site/:site_id' => 'home#index'
resources 'sites'
end
end
sites_controller.rb:
class SitesController < ApplicationController
def show
render json: File.open('data/sites.json').read
end
end
models/site.js.coffee:
App.Site = DS.Model.extend()
data/sites.json
{
"site": [
{
"id": "1",
"name": "Place One",
"type": "Type One"
}, {
"id": "2",
"name": "Place One",
"type": "Type Two"
}
]
}

Related

How to set a url routing in Rails?

I want to set this routing:
http://localhost:3000/sites/search/www.google.com
My config/routes.rb
resources :sites, only: [:index] do
collection do
get 'search/:url', to: 'sites#search'
end
end
Routes:
GET /v1/sites/search/:url(.:format) v1/sites#search {:format=>:json}
Controller
def search
#url = params[:url]
end
But when I access from URI
http://localhost:3000/sites/search/www.google.com
Got
{
"status": 404,
"error": "Not Found",
"exception": "#<ActionController::RoutingError: No route matches [GET] \"/sites/search/www.google.com\">",
"traces": {
"Application Trace": [],
A . in a url has a specific meaning, and hence can't be used directly. To handle all possible URLs in your queries, you should encode the urls before sending them in your query parameters. So
http://localhost:3000/sites/search/www.google.com
will become
http://localhost:3000/sites/search/www%2Egoogle%2Ecom
Edit:
There's actually a better solution that is more Railsy. By default, Rails expects the . to be a separator in your URL. However Rails allows you to define the format expected for your parameters using constraints.
So if you update your route definition by adding a regex constraint for the url parameter,
get 'search/:url', to: 'sites#search', constraints: { url: /.*/ }
you should now be able to handle even URLs like,
http://localhost:3000/sites/search/www.google.com

Rails is it possible to have a link_to that passes param to jquery datatable filter?

I am using Rails 5 and Jquery Datatables in an app. I have a filter field on my datatable. I would like for people to be able to click on a tag and get the main table filtered by that tag. The seemingly easy way to do it would be to have a link_to like this:
posts_path(post: {filter: 'science'})
This creates the URL like:
http://localhost:3000/posts?post%5Bfilter%5D=science
I then have this in my controller index action:
#posts = Post.all
#filter = post_params[:filter]
Which is using the standard strong params method like:
def post_params
params.require(:post).permit(:filter ...)
end
Then in the Javascript for the DataTable I did this:
$('#posts_table').dataTable({
saveState: true,
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]],
search: {
search: '<%= #filter %>'
},
"columnDefs": [
{
"targets": [-1],
"visible": false,
"searchable": true
}
]
});
It works great!! The page loads with the table filtered on the search term and the term appears in the search text box. But when I call the index page without any params it fails:
http://localhost:3000/posts
ActionController::ParameterMissing at /posts
param is missing or the value is empty: post
which I get because no params are being sent but I'm calling the params method. Is there a simple way to fix this? i.e. could I make the default route have a default param with an empty string as the search term? What would the correct syntax for that route be? I was thinking I could set the params to '' if undefined but not sure how to do that with Strong Params in a way that would not compromise security.
Well I knew this couldn't be too difficult and was probably over-thinking it. I finally just made a route for tags thus:
get 'tags', to: 'posts#by_tag', as: :filter, :constraints => { :filter => /[^\/]+/ }
Then I added a controller action called by_tag like this:
def by_tag
#posts = Post.all
#filter = post_params[:filter]
respond_to do |format|
format.html { render :index }
end
end
then to create my tag links I just do something like:
tags.each do |t|
link_to t.name, filter_path(post: {filter: t.name})
end
which creates links like:
http://localhost:3000/tags?post%5Bfilter%5D=9500XL
And with the JavaScript mentioned in the question I get the table loaded with the filter applied in the search field.
Something about the by_tag action feels a bit un-rails-ish. I feel like I'm missing something simple that would allow me to leverage the index action for this. If anyone has a better answer I'd love to know.

ActiveModel Serializer::Pagination not working with ActionController::Parameters

Setup:
Rails 5, using ActiveModel::Serializer and Kaminari
Sample code:
def index
#catalogs = Catalog.page(params[:page])
render json: #catalogs, adapter: :json_api
end
Problem:
When params[:page] is nil, my result is as expected:
{
"data": [
{
"id": "a020ab21-9028-4bfd-8f9c-1b735ed4734b",
"type": "catalogs",
"attributes": {
"name": "First",
"locale": "en"
}
}
],
"links": {
"self": "http://localhost:3000/v1/catalogs?page%5Bnumber%5D=1&page%5Bsize%5D=1",
"next": "http://localhost:3000/v1/catalogs?page%5Bnumber%5D=2&page%5Bsize%5D=1",
"last": "http://localhost:3000/v1/catalogs?page%5Bnumber%5D=3&page%5Bsize%5D=1"
}
}
However, when I make a Postman call to the "next" URL (http://localhost:3000/v1/catalogs?page%5Bnumber%5D=2&page%5Bsize%5D=1),
I get:
Started GET "/v1/catalogs" for 172.18.0.1 at 2017-09-08 15:27:04 +0000
undefined method `to_i' for #<ActionController::Parameters:0x0000c68977f718>
Did you mean? to_s
to_h
Is there something different that has to be done with Rails 5 params to get pagination for ActiveModel::Serializers to work?
It appears params[:page] doesn't hold the page number, but a "hash": { number: 1, size: 1 }. That said, you want to use the page number as the argument to page:
def page_params
params.fetch :page, {}
end
#catalogs = Catalog.page(page_params[:number])
Maybe even call .per(page_params[:size]) too, to let the API change that as well.
Solution:
I encountered nested pagination params problematic in some cases. You could use params page and per_page instead of page[number] and page[size]. Solution for will_paginate is in this comment on GitHub issue. Solution is probably also for kaminari, because its the issue of serialization gem, not pagination gem.
Explanation:
As Leonel explained, link that you are clicking:
localhost:3000/v1/catalogs?page%5Bnumber%5D=2
is the same as:
localhost:3000/v1/catalogs?page[number]=2
so your code should access these params like:
params[:page][:number]
not:
params[:page]
Solution from above, using ActiveModel::Serializers will create links like this:
localhost:3000/v1/catalogs?page=2&per_page=50
So you can access pagination params like you want in your controller:
Catalog.page(params[:page]) # page number
Catalog.per(params[:per_page]) # page size

Ruby on Rails api json response methods and include

I have technical question i have user model which have many questions so in my API controller i do:
render json: user, :include => {
:questions => {
:only => [:text]
},
}
Now i want to add to JSON response question count. How can i do that in best way. I know that i can create method inside model : count_question and after that do:
render json: user, :include => {
:questions => {
:only => [:text]
},
}, :methods => [
:count_question
]
and my response will be good. But is there better way to put that information to JSON. I want to avoid add method inside model. Is it possible to determine this count inside json renderer?
Greetings
Checkout JSON API and Active Model Serializers with Rails
This will hep you out format your JSON.

How to group/nest routes in rails like you can in laravel?

I'm switching from using a laravel php framework to a rails framework and cannot figure out how to get nested routes working in rails like it did in laravel. In laravel it would work like this:
Route::group(['prefix' => 'healthandwelness'], function() {
Route::get('', [
'uses' => 'healthandwelness#index'
]);
Route::group(['prefix' => 'healthcare'], function() {
Route::get('', [
'uses' => 'healthcare#index'
]);
Route::get('{article_id}', [
'uses' => 'article#index'
]);
]);
});
Which would give me the routes:
/healthandwellness
/healthandwellness/healthcare
/healthandwellness/healthcare/{article_id}
The only way I've seen to nest routes in rails is with resources which I've used to tried and recreate my routes in rails like this:
resources :healthandwellness do
resources :healthcare
end
But the nature of resources makes this route into the following gets:
/healthandwellness
/healthandwellness/:health_and_wellness_id/healthcare
/healthandwellness/:health_and_wellness_id/healthcare/:id
Is there anyway to do what I am looking for in rails and recreate what I was able to do laravel?
You can use namespace:
namespace :healthandwellness do
resources :healthcare
end
Note that this assumes that your controller is located in app/controllers/healthsandwellness/healthcare_controller.rb and should be defined as follows:
class Healthandwellness::HealthcareController < ApplicationController
...
end
If you want to keep your controller under apps/controller and not scoped under app/controllers/healthandwellness, you can use scope:
scope '/healthandwellness' do
resources :healthcare
end
The documentation here provides good examples of namespace and scope

Resources