i just can not figure out the best way to handle the routes / controller with the following namespace.
i´d just like to have the following setup:
.../manage/rooms/ ( <%= # rooms.number_of_rooms%>, <%= # rooms.title %> )
.../manage/fuu/ ( <%= # fuu.id %>...)
..manage/foo/ ...
i know this is done by
routes.rb
namespace :manage do
resources :rooms, :fuu, :foo
end
and under ...controller/manage/rooms_controller.rb and fuu_controller.rb and foo...
example:
class Manage::RoomsController < ApplicationController
index
#rooms = Rooms.all
end
def create
#room = Room.new(room_params)
if #room.save
redirect_to [:manage, #room]
else
render 'new'
end
...
end
and a controller under controller/manage_controller.rb
class ManageController < ApplicationController
end
so here is my question i do like to use all of my forms and variables #rooms.title...who are under .../manage/rooms/ .../manage/fuu/ ....
under the .../manage/index.html.erb
is the best way to do it via the controller e.g. render partial or changing the controller which the routes point to?
thanks!!!
I would use partials in this situation. If they are all shared in that namespace, it makes sense for the location to be the manage views directory. If they weren't namespaced but still being shared, I'd create a 'shared' directory in views.
Related
I'm new to rails, and I've already learnt how to do CRUD using scaffold and using resource, I wanna know how to Do CRUD without using resource, However what I want to do is create custom methods for CRUD in the controller that will be like the traditional CRUD model. Please help me with this.
Actually, for the action index / new / show / create / edit / update / destroy, this is a convention in Ruby On Rails
If I'm right and if you're trying to change their name using resources in routes.rb (Changing by exemple the new action into def my_restaurant), Rails will render
Unknown action The action 'new' could not be found for
RestaurantsController
Netherless, you can create some methods to perform some particular action into the index, and add them in the "private section" you want to hide them to the public. There is no routes attach to this method.
class RestaurantsController < ApplicationController
def index
#restautants = Restaurant.all
#restaurants.sort_by_name
end
private
def sort_by_name
#some action here
end
end
If you want to create your own name method, you can personnalise it but you can't use resources "shortcut" in the routes.rb
by exemple :
#reviews_controller.rb
class ReviewsController < AplicationController
def index
#reviews = Reviews.all
end
def update
#review = Review.find(review_params[:id])
end
def history
#some action
end
private
def review_params
params.require(:review).permit(:liked, :comment, :id)
end
end
Then add a view
#app/views/reviews/history.html.erb
Don't forget the routes :
Rails.application.routes.draw do
resources :reviews, only: [:index, :update] do
collection do
get :history
end
end
end
I hope this will help you and complete the previous answer.
as for your second question :
I still do have one doubt tho..... Will <%= form_for #post do |f| %>
this form be enough for new_post and edit_post, will it automatically
identify them? If that's not enough can you please tell me the what
comes at new_post.html.erb and edit_post.html.erb....Thanks again for
the help.
If the form is the same for your new_post and edit_post, i may suggest you to put into a partial file. (For this example I used simple_form gem)
#app/views/posts/_form.html.erb
<%= simple_form_for(#post) do |f| %>
<%= f.input :name, label: "post name" %>
<%= f.input :photo, as: :file %>
<%= f.submit "Save", class:"btn btn-small btn-success" %>
<% end %>
and then render the partial in your views new file.
#app/views/posts/new.html.erb
<div>
<h1>New Post</h1>
</div>
<%= render "form" %>
Well I hope I could help you with this answer.
Do not hesitate too to read ruby documention. You may find more information that you're looking for too.
My answer may be redundant but it's the better way for me to clearly explain it...
In oder to use your own custom methods you need to create them in your controller, setup the route and if needed create an view.
# PostsController
def create_post
# Do your create stuff here
end
def read_post
# Do your read stuff here
end
def update_post
# Do your update stuff here
end
def delete_post
# Do your delete stuff here
end
# routes
post '/create_post', to: 'posts#create_post'
get '/read_post/:id', to: 'posts#read_post'
put '/update_post/:id', to: 'posts#update_post'
delete 'delete_post/:id', to: 'posts#delete_post'
With the controller and routes setup you will only need a view for the read_post method. The best way to do that is create the file: views/posts/read_post.html.erb
There is 7 CRUD routes to Create, Read, Update and Delete.
Rails.application.routes.draw do
get "restaurants", to: "restaurants#index"
get "restaurants/new", to: "restaurants#new", as: :new_restaurant
post "restaurants", to: "restaurants#create"
# NB: The `show` route needs to be *after* `new` route.
get "restaurants/:id", to: "restaurants#show", as: :restaurant
get "restaurants/:id/edit", to: "restaurants#edit", as: :edit_restaurant
patch "restaurants/:id", to: "restaurants#update"
delete "restaurants/:id", to: "restaurants#destroy"
end
So once the route create, you can create in the controller, the action that you need
class RestaurantsController < ApplicationController
def index
#restaurants = Restaurant.all
end
end
and the view
app/views/restaurants/index.html.erb.
The best practice is to create only the routes that you will need and to work in silos.
1 route, 1 controller action, 1 view.
When I go to the characters controller, show action, all the normal params[:id] is as how it should be according to REST.
In the show view, I render a partial. In that partial, I have a link that goes to the vote_socionics action. This action is defined under a socionics_votes module, which gets included by the characters controller. (I have it set up this way because I have other controllers that also include this module).
My problem is that when I click on this link, and it goes to the set_votable private method within the socionics_votes_module.rb file, the params[:id] is no longer present. Using pry, I found that it actually turns into params[:character_id]
Questions:
1) Why does this happen (is it because it goes to a "different" controller, even if it's a module?)
2) How do I work around this? I would think that it would be more elegant to have it be params[:id], instead of having to do an if-else to account for both keys.
characters_controller.rb
class CharactersController < ApplicationController
include SocionicsVotesModule
def show
#character = Character.find(params[:id])
end
characters/show.html.haml
= render partial: 'votes/vote_socionics',
locals: { votable: #votable, votable_name: #votable_name, socionics: #socionics }
_vote_socionics.html.haml
= link_to content_tag(:div,"a"), send("#{votable_name}_vote_socionics_path", votable, vote_type: "#{s.type_two_im_raw}"),
id: "vote-#{s.type_two_im_raw}",
class: "#{current_user.voted_on?(votable) ? 'voted' : 'not-voted'}",
method: :post,
data: { id: "#{s.type_two_im_raw}" }
socionics_votes_module.rb
module SocionicsVotesController
extend ActiveSupport::Concern
included do
before_action :set_votable
end
private
def set_votable
votable_constant = controller_name.singularize.camelize.constantize
#votable = votable_constant.find(params[:id]) # This is where it fails, since there is no params[:id], and rather, params[:character_id]
end
def set_votable_name
#votable_name = controller_name.singularize.downcase
end
routes.rb
concern :socionics_votes do
post 'vote_socionics'
end
resources :characters, concerns: :socionics_votes
resources :celebrities, concerns: :socionics_votes
resources :users, concerns: :socionics_votes
The URL of the link in the partial when hovered over.
localhost..../characters/4-cc/vote_socionics?vote_type=neti
Something like .find(params[:id] || params[:"#{#votable_name}_id"]) didn't work, and seems silly.
You need to add the vote_socionics route as a member of the resource:
concern :socionics_votes do
member do
post 'vote_socionics'
end
end
This way the id parameter gets set correctly
I have such method controller:
class Admin::CarManufacturersController < ApplicationController
def edit
#man = Manufacturer.find(params[:id])
render :layout => 'admin'
end
def update
#man = Manufacturer.find(params[:id])
if #man.update_attributes(params[:car_manufacturer])
****
else
render :action => :edit, :layout => 'admin'
end
end
end
and i have such route:
namespace :admin do
resources :car_manufacturers do
###
end
end
and such form partial:
= form_for [:admin, #man] do |f|
###
but when i call this form to edit my data i get:
undefined method `admin_manufacturer_path'
but i need admin_car_manufacturer_path i thing it's becouse i use other model name in controller, but i can't change it... how can i use right pass? i try to write admin_car_manufacturer_path in form, but i think this is bad idea. How to solve my problem?
I would think about renaming your controller/your model to match. Both should either be just manufacturer or car manufacturer. Having the same names for a resource's controller and model will spare you problems like the one you're having right now.
In any case, if you just need a quick fix, you can get around this by specifying the as option for your nested routes like this:
namespace :admin do
resources :manufacturers, as: :car_manufacturers do
###
end
end
Source: Rails Routing from the Outside In - Ruby on Rails Guides - 3.6: Naming Routes
That will turn your path names into admin_car_manufacturer_path etc and should allow you to use your form the way you you intended to. But I really recommend renaming your model and controller so that they match.
I'm just started with rails and until now I was very happy with it, but there is one thing I can't figure out.
I have some ActiveRecords models in a namespace "Monitor", and I have some controllers in a Namespace "Settings". What I want to accomplish is that I can use the namespaced models in my settings controllers/forms.
I've got this:
/config/routes.rb
namespace :settings do
resources :queues, :channels
end
/app/controllers/settings/queus_controller.rb
class Settings::QueuesController < ApplicationController
def new
#queue = Monitor::Queue.new()
render 'form', :layout => false
end
def create
#queue = Monitor::Queue.new(post_params)
if (#queue.save)
#status = 'added'
render 'success'
else
render 'form', :layout => false
end
end
def edit
#queue = Monitor::Queue.find(params[:id])
render 'form', :layout => false
end
...
end
/app/models/monitor/queue.rb
module Monitor
class Queue < ActiveRecord::Base
end
end
/app/views/settings/form.html.erb
<%= form_for #queue do |f| %>
...
<% end %>
Now Rails is complaining about a missing method : monitor_queues_path or Rails generates a path like /monitor/queues instead of /settings/queues(:new/edit).
What am I missing here?
Aah I found it!
This post gave me the proper solution:
Rails namescoped model object without module prefix route path
The problem came from the prefix from the ActiveRecord class:
module Monitor
class Queue < ActiveRecord::Base
end
end
This should be
module Monitor
class Queue < ActiveRecord::Base
def self.model_name
ActiveModel::Name.new("Monitor::Queue", nil, "Queue")
end
end
end
After changing this I only needed to change the form_for in the correct way:
<%= form_for [:settings, #queue] do |f| %>
And that fixes it :D
You are using nesting for your Queue models. Therefore your form_for call needs to know about the parent model too. So in your case you nested Queue under Setting so you will need to provide a setting object as well. I'm guessing in your controller you made a #setting variable. If this is the case then the following code will work for you.
<%= form_for [#setting, #queue] do |f| %>
<%# Your form code here -%>
<% end -%>
I found a solution from my friend #mkhairi he said to use this on the parent model :
class YourParentModel < ApplicationRecord
def self.use_relative_model_naming?
true
end
end
then you can use back ur lovely short path.
Source :
https://coderwall.com/p/heed_q/rails-routing-and-namespaced-models
Implementing versioning for a Rails app I'd like to have a view that displays all versions of a model with some extra functionality like reverting etc.
I use the paper_trail gem for the versioning.
I know that I could do that by writing a controller function like versions and a view for every model but I'd like to do it for all models at once. This should be possible because the model.versions attribute is always structured identically.
Ideally the URL should look like /pages/testpage/versions while testpage is the page id.
This seems similar to the concept of nested routes in rails.
resources :pages do
resources :versions
end
The problems with nested routes however are:
Needs extra configuration per model
I cannot access the testpage object without knowing of which model it is an instance.
I also wasn't able to find a way to determine the model since the only thing that is provided to my versions controller is the params hash.
I'm completely open to alternative solutions that might not follow my initial ideas.
Write it in your ApplicationController and define it as a helper_method.
For example
class ApplicationController < ActionController::Base
helper_method :current_time
def current_time
Time.now
end
end
Now you can cal current_time everywhere in controllers or views.
Also you can write separate Module/Class and define there your helpers methods. Than you should include this file into your ApplicationController as well
UPD after theme is changed
I didn't think about your actual question. But I can say that your approach is nod the best here.
You should create new resource instead of creating new functionality which will hard to be tested. So create new resource (controller): versions and play around this controller.
For example how it can work:
/versions/pages/132
/versions/comments/1003
How to realize it:
match "/versions/:model/:id", :to => "versions#index"
In your controller:
class VersionsController < ActionController::Base
def index
#object = my_type.find(params[:id])
#versions = #object.versions
end
private
def my_type
params[:model].constantize
end
end
Of course you can change routes the way you want:
match "/:model/:id/versions", :to => "versions#show"
So now your pretty /pages/testpage/versions will work fine for you without any new strange logic.
UPD 2
Imagine you have got this route:
match "/:model/:id/versions", :to => "versions#index", :as => :versions
And this objects:
#page = Page.last
#hotel = Hotel.find(123)
#comment = #page.comments.first
How will we create links for versions:
<%= link_to "Versions of this page", versions_path(:model => #page.class.to_s, :id => #page.id) %>
<%= link_to "Versions of this hotel", versions_path(:model => #hotel.class.to_s, :id => #hotel.id) %>
<%= link_to "Versions of this comment", versions_path(:model => #comment.class.to_s, :id => #comment.id) %>
I would suggest passing a param such as 'type' and stuff the model name there. Then in your controller you can do:
class VersionsController < ApplicationController
def index
model = params[:type].classify.constantize
#obj = model.find(params[:id])
end
end
For your links, you can pass queries to the link_to helper
<%= link_to versions_path(#model, :type => #model.class) %>
Or something along those lines.