How to render nested resources as json in rails if each nested resource could also have resource nested under it?
If you can use custom methods for preparing json, this is how you can do that:
class List
has_one :item
def custom_json
json = to_json
json[:item] = item.custom_json
json
end
end
class Item
has_many :items # add other options
def custom_json
json = to_json.merge(children: [])
items.each { |item| json[:children] << item.custom_json }
json
end
end
Note: here items
refer to the relation you have in Item
class for its child items.
And in your controller, you could do
format.json { render json: @list.custom_json }
This would result in json structure:
{ list_attr: value, list_attr_2: value, item: { item_attr: value, children: [{ child_item_attr: value, ... }] } }
Let me know if it helps.
Simple Acts_as_tree with nested_resources
A)
If you have a solution for the routing and the only problem with it is that you're concerned about duplicate content issues, you could consider adding <link rel="canonical" href="...">
to the pages generated from those requests. It's not bulletproof though, as Google considers it a suggestion.
Not sure if the route globbers solution would take care of generating the URLs with parent IDs though.
B)
You don't need the parent IDs to perform the routing, correct? You just want to include them in the URLs and route those requests the same as if using the URLs like example.com/chapter1
, correct?
If you'd consider a solution that's not purely at the Rails level, what about rewriting the URLs on those requests so that /:parent_id/:parent_id/:id
becomes /:id
before Rails processes it? That would be easier if there was a static prefix, like /articles/:parent_id/:parent_id/:id
.
I imagine you'd need to write some helpers to generate the URLs with parent IDs for linking to those resources.
Duplicate Content
Either way, you'll need to generate URLs that include the parent IDs, so duplicate content issues probably aren't too likely if you only link to those resources using those URLs.
Recursion for nested list generation
I am not too sure everything that your code is doing, but it seems you want something like this
def process_topics topics_list
topics_list.each do |t|
# do something
process_topics children_of_topic(topic_list, t)
# or do something
end
end
def children_of_topic(topic_list, topic)
topic_list.select(|t| t.id == topic.parent_id)
end
It might be good to simplify your example down to something like this then add stuff in as you go.
Your very first call
get_nested_list(topics_list, topics_list.first)
Is not making sense. You want to cycle through each topic in your list and get the children of that topic and then recurse on that.
Rails nested resources and :path = /
A couple ways of doing this...
1) Will give you routes like /:user_id/:id
(which you wanted)
match '/:user_id/edit', :to => 'users#edit', :as => :edit_user
resources :users, :except => [:edit], :path => "/" do
resources :projects, :path => "/"
end
2) Will give you routes like /:user_id/projects/:id
(which it seems like you're avoiding)
resources :users, :path => "/" do
resources :projects
end
I personally prefer #2 since it is cleaner and provides more knowledge about the route at a glance.
Rails 6 - Issue with nested resources in a namespace
If you do rails routes
, you'll get (amongst other things):
Prefix Verb URI Pattern Controller#Action
account_management_pages_registration GET / account_management_pages/users#new
account_management_pages_user_user_profiles GET /users/:user_id/user_profiles(.:format) account_management_pages/user_profiles#index
POST /users/:user_id/user_profiles(.:format) account_management_pages/user_profiles#create
new_account_management_pages_user_user_profile GET /users/:user_id/user_profiles/register(.:format) account_management_pages/user_profiles#new
edit_account_management_pages_user_user_profile GET /users/:user_id/user_profiles/:id/edit(.:format) account_management_pages/user_profiles#edit
account_management_pages_user_user_profile GET /users/:user_id/user_profiles/:id(.:format) account_management_pages/user_profiles#show
PATCH /users/:user_id/user_profiles/:id(.:format) account_management_pages/user_profiles#update
PUT /users/:user_id/user_profiles/:id(.:format) account_management_pages/user_profiles#update
DELETE /users/:user_id/user_profiles/:id(.:format) account_management_pages/user_profiles#destroy
account_management_pages_users POST /users(.:format) account_management_pages/users#create
new_account_management_pages_user GET /users/register(.:format) account_management_pages/users#new
edit_account_management_pages_user GET /users/:id/edit(.:format) account_management_pages/users#edit
account_management_pages_user GET /users/:id(.:format) account_management_pages/users#show
PATCH /users/:id(.:format) account_management_pages/users#update
PUT /users/:id(.:format) account_management_pages/users#update
DELETE /users/:id(.:format) account_management_pages/users#destroy
As you can see, user_profiles
is not nested under the users
namespace. Rails, therefore, is expecting:
module AccountManagementPages
class UserProfilesController < ApplicationController
...
end
end
If you do:
constraints(AccountManagement) do
namespace :account_management_pages, path: '' do
root to: 'users#new', as: :registration
resources :users, except: %w[index], path_names: { new: 'register' } do
scope module: :users do
resources :user_profiles
end
end
end
end
...and then rails routes
, you get (amongst other things):
Prefix Verb URI Pattern Controller#Action
account_management_pages_registration GET / account_management_pages/users#new
account_management_pages_user_user_profiles GET /users/:user_id/user_profiles(.:format) account_management_pages/users/user_profiles#index
POST /users/:user_id/user_profiles(.:format) account_management_pages/users/user_profiles#create
new_account_management_pages_user_user_profile GET /users/:user_id/user_profiles/register(.:format) account_management_pages/users/user_profiles#new
edit_account_management_pages_user_user_profile GET /users/:user_id/user_profiles/:id/edit(.:format) account_management_pages/users/user_profiles#edit
account_management_pages_user_user_profile GET /users/:user_id/user_profiles/:id(.:format) account_management_pages/users/user_profiles#show
PATCH /users/:user_id/user_profiles/:id(.:format) account_management_pages/users/user_profiles#update
PUT /users/:user_id/user_profiles/:id(.:format) account_management_pages/users/user_profiles#update
DELETE /users/:user_id/user_profiles/:id(.:format) account_management_pages/users/user_profiles#destroy
account_management_pages_users POST /users(.:format) account_management_pages/users#create
new_account_management_pages_user GET /users/register(.:format) account_management_pages/users#new
edit_account_management_pages_user GET /users/:id/edit(.:format) account_management_pages/users#edit
account_management_pages_user GET /users/:id(.:format) account_management_pages/users#show
PATCH /users/:id(.:format) account_management_pages/users#update
PUT /users/:id(.:format) account_management_pages/users#update
DELETE /users/:id(.:format) account_management_pages/users#destroy
...and user_profiles
will be nested under users
. And you should be able to use:
module AccountManagementPages
module Users
class UserProfilesController < ApplicationController
...
end
end
end
Finding the parent object in a nested resource relationship?
Routing will not help you as this is only meant to be used the other way around.
What you can do is aliasing the relationship with :parent:
class Task
belongs_to :project
alias :project :parent
end
And then use this relationship to detect if a parent object is available:
if object.respond_to?(:parent)
# do something
end
Moreover, you can use polymorphic routes if the routes are set up correctly:
polymorphic_url([object.parent, object])
Related Topics
How to Reduce the Quality of an Uploading Image Using Paperclip
How to Fix in Ruby on Rails the Undefined Method 'Alias_Method_Chain' Error
Bundle Install Is Using a Different Ruby Version
Error While Installing Iconv on Windows by Ruby2.0.0
Regex Negative Lookbehind in Ruby Doesn't Seem to Work
Execute Code Once Sinatra Server Is Running
Ruby on Rails Workflow Engine (Like Ibm Workflow)
Rails Cannot Find Model with Same Name as Ruby Class
How to Serialize as Activesupport::Hashwithindifferentaccess Anymore
Passing Variables on the Command Line to a Cucumber Test
While Executing Gem ... (Argumenterror) Unknown Encoding Name - Cp720
How to Make Empty Tags Self-Closing with Nokogiri
Disabling Irb Autocomplete on Heroku
Algorithm to Shuffle an Array Randomly Based on Different Weights
Chrome Asks to "Select a Certificate" for Ssl on My Rails App Using Thin