Rails - passing object's id - ruby-on-rails

I'm creating a message-board site using ruby on rails.
I generated two scaffolds: Topic and Forum. Topic belongs_to Forum.
when the user is creating a new topic, I should pass the forum_id (a GET var). something like:
http://example.com:3000/topics/new/1
and then, when the user submit the form he passes back the forum_id with the POST request (through hidden html field?).
what is the right way doing it?
thanks
routes:
resources :forums
get "admin/index"
resources :posts
resources :topics
resources :users
match '/signup', :to => 'users#new'
get '/login', :to => 'sessions#new', :as => :login
match '/auth/:provider/callback', :to => 'sessions#create'
match '/auth/failure', :to => 'sessions#failure'
match '/topics/new/:id', :to => 'topics#new'

A good way to do it is to nest topics resources inside forums resources like this:
resources :forums do
resources :topics
end
Then in your TopicsController
class TopicsController < ApplicationController
def new
#forum = Forum.find params[:forum_id]
#topic = Topic.new
end
def create
#forum = Forum.find params[:forum_id] # See the redundancy? Consider using before_filters
#topic = #forum.topics.build params[:topic]
if #topic.save
redirect_to #topic
else
render action: :new
end
end
end
And finally in your views/topics/_form.html.erb:
<%= form_for [#forum, #topic] do |f| %>
# Your fields
<% end %>

Related

routes error in rails

I am working on a project. I am making an application where a user can add an issue (like a post) and the user can comment on it.
on running this application, I get an error
Couldn't find Issue with 'id'=show
the code for routes file is
resources :issues do
resources :comments
end
get 'users/new'
get 'users/create'
get 'users/show'
get 'users/edit'
get 'issues/show/:id', :to => 'issues#show'
resources :users
resources :sessions, :only => [:create, :new,:destroy]
get '/signup', :to => 'users#new'
get '/signin' , :to => 'sessions#new'
get '/signout', :to => 'sessions#destroy'
the code for the issues controller is
class IssuesController < ApplicationController
def new
#issue = Issue.new
end
def create
#issue = Issue.new(issues_params)
if #issue.save
flash[:success]='your issue has been raised'
redirect_to :controller => 'issues', :action => 'show', :id => #issue.id
else
render 'new'
end
end
def edit
#issue = Issue.find(params[:id])
end
def update
#issue = Issue.find(params[:id])
if #issue.update_attributes(issues_params)
redirect_to :controller => 'issues', :action => 'show', :id => #issue.id
else
render 'edit'
end
end
def index
#issues = Issue.all
end
def show
#issue = Issue.find(params[:id])
end
def destroy
#issue=Issue.find(params[:id])
#issue.destroy
redirect_to :controller => 'issues', :action => 'index'
end
protected
def issues_params
params.require(:issue).permit(:title,:content)
end
end
the code for the comments controller from where I call the show method in issues controller is
class CommentsController < ApplicationController
def create
#issue = Issue.find(params[:issue_id])
#comment = #issue.comments.create(comment_params)
if #comment.save
redirect_to :controller => 'issues', :action => 'show', :id => #issue[:id]
else
render 'new'
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
You must be trying to request the URI /issues/show? This will map to the GET /issues/:id from the resources :issues do line of your routes. The router will set the params[:id] to the string "show" and send the request to the show action of the IssuesController which, as you've shown, will then try to do Issue.find(params[:id]) ie. Issue.find("show") and hence you get your error.
Change this
resources :issues do
resources :comments
end
to
resources :issues, except: [:show] do
resources :comments
end
It will resolve your problem!

Can't find user without ID - form error in Rails 4 project

I'm working on "Edit profile" part with Ruby on Rails.
the route.rb is:
Rails.application.routes.draw do
get 'courses/index'
get 'courses/new'
get 'courses/edit'
get 'courses/show'
get 'course/index'
get 'course/new'
get 'course/edit'
get 'course/show'
get 'sessions/login'
get 'sessions/main'
get 'sessions/profile'
get 'sessions/setting'
get 'users/new'
get 'home/index'
resources :users
resources :sessions
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'home#index'
# Example of regular route:
# get 'products/:id' => 'catalog#view'
# Example of named route that can be invoked with purchase_url(id: product.id)
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
# Example resource route (maps HTTP verbs to controller actions automatically):
resources :courses
# Example resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Example resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Example resource route with more complex sub-resources:
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', on: :collection
# end
# end
# Example resource route with concerns:
# concern :toggleable do
# post 'toggle'
# end
# resources :posts, concerns: :toggleable
# resources :photos, concerns: :toggleable
# Example resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
match '/about', to: 'home#about', via: 'get'
match '/signup', to: 'users#new', via: 'get'
match ':controller(/:action(/:id))(.:format)', via: 'get'
match '/signin', to: 'sessions#new', via: 'get'
match '/signout', to: 'sessions#destroy', via: 'delete'
match '/main', to: 'users#new', via: 'get'
#match '/profile', to: 'sessions#profile', via: 'get'
match '/setting', to: 'sessions#setting', via: 'get'
match '/editname', to: 'users#edit', via: 'get'
match '/show', to: 'users#show', via: 'get'
match '/profile', to: 'users#profile', via: 'get'
#match '/info', to: 'users#info', via: 'get'
#match '/changepass', to: 'users#edit', via: 'get'
end
My users_controller.rb is:
class UsersController < ApplicationController
before_filter :check_if_signned_in, only: [:show, :delete]
before_filter :signed_in_user, only: [:edit, :update]
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to #user, notice: 'User was sucessfully created!'
else
render action: "new"
end
end
def show
#user = User.find(params[:id])
end
def edit
##user = User.find(current_user.id)
#user = User.find(params[:user_id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated."
sign_in #user_params
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
def signed_in_user
redirect_to signin_path, notice: "Please sign in." unless signed_in?
end
end
And, the sessions_controller.rb is:
class SessionsController < ApplicationController
def new
end
def create
user = User.authenticate(params[:session][:email], params[:session][:password])
if user.nil?
flash.now[:error] = "Invalid email or password."
render :new
else
sign_in user
redirect_to user
end
end
def destroy
sign_out
redirect_to signin_path
end
end
the edit.html.erb is:
Editing profile
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Update", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
the sessions_helper.rb is:
module SessionsHelper
def sign_in(user)
session[:user_id] = user.id
self.current_user = user
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def signed_in?
!current_user.nil?
end
def sign_out
session[:user_id] = nil
self.current_user = nil
end
def current_user?(user)
user == current_user
end
def deny_access
redirect_to signin_path, :notice => "Please sign in first."
end
end
The error is: in the code below
def edit
***#user = User.find(params[:user_id])***
end
it Couldn't find User without an ID
How can i fix this problem please?
And moreover, the version of my rails is: 4.1.2, it seems the thing "update_attributes" doesn't work, is that true? How can I make "edit profile" function without using update_attributes please?
Thank you!
Routes
Firstly, you'll be much better DRYing up your routes:
#config/routes.rb
resources :courses, only: [:index, :new, :edit, :show]
resource :course, only: [:index, :new, :edit, :show] #-> singular resource (not sure if you want)
resources :sessions, path_names: {new: "signin", destroy: "signout"} do
collection do
get :login
get :main
get :profile
get :setting
end
end
resources :users, path_names: {new: "signup"} do
collection do
get "main", action: :new
end
end
resources :home, only: [], path: "" do
get :about
end
You have to remember Rails, and by virtue, its routing structure, is resource-based (resourceful). This means everything you do needs to be centered on an ActiveRecord Object (oft called a "resource") - this is why Rails' routing is based on resources :)
Your routes were NOT resource-based, and hence very confusing
--
Fix
When you receive the error:
Couldn't find User without an ID
It basically means you aren't passing the required ID parameter to your controller, hence preventing your application from being able to identify the object required to populate your form.
This will either be caused by not passing the params[:id] to your /profile controller, or you're calling the wrong variable name
-
I would initially look at your routes
You need to appreciate the importance of collection vs member routes - member routes are basically designed for individual element. I believe you're not passing the parameter your edit action needs, hence preventing your application from assigning a value to the #edit variable
You're either going to need to use a session to access the User.id, or use a member route (which will pass the id in the url)

Connection between controller and view in rails

In users_controller.rb I've got my method:
def showallusers
#users = User.all
respond_to do |format|
format.html # showallusers.html.erb
format.json { render :json => #users }
end
end
and in app/views/users I've got showallusers.html.erb and in it:
<p>test</p>
but when I type
http://localhost:3000/users/showallusers
in browser, it shows me show.html.erb instead.
My routes.rb
resources :users
resources :projects do
resources :issues
end
#resources :issues
resources :projects
resources :sessions
root :to => "users#index"
match "/auth/:provider/callback" => "sessions#create"
match "/signout" => "sessions#destroy", :as => :signout
Do you know, what is wrong and how can I fix it? thanks
In your routes.rb:
resources :users do
collection do
get :showallusers # why not :show_all_users? Isn't it more readable?
# you may also need
# post :showallusers
end
end
Then restart your server to make sure the new url-helpers are generated (the new helper should be showallusers_users_path)

Rails: Routing Issue, Button to Bring up partial

I have a school page that has tabs when clicked upon are suppose to bring up microposts. The issue is I don't think I am routing it correctly and I feel like an idiot trying to figure this out and not succeeding. If anyone has suggestions please feel free to help me out! Thank you so much!
Routes.rb
get "/schools/:id/mostrecent_schools" => "users#microposts", :as => "mostrecent_schools"
School Controller
def mostrecent
#school = School.find_by_slug(request.referer.gsub('http://localhost:3000/','')).id
#microposts = #user.microposts.paginate(:per_page => 10, :page => params[:page])
respond_to do |format|
format.html
format.js
end
end
Tab HTML
li class='StreamTab StreamTabRecent active'>
<%= link_to 'Most Recent', mostrecent_schools_path, :remote => true, :class => 'TabText' %>
</li>
<div id='ContentBody'>
<div id='ajax'></div>
<%= render 'users/microposts', :microposts => #microposts %>
</div>
mostrecent.js
$("#ajax").hide();
$("#ContentBody").html('<%= escape_javascript(render :partial => "users/microposts" )%>');
EDIT
*Routes.rb*
Projects::Application.routes.draw do
resources :pages
resources :application
resources :schools
resources :microposts
resources :comments
resources :users
resources :sessions
resources :password_resets
resources :relationships, only: [:create, :destroy]
resources :users do
member do
get :following, :followers
end
end
resources :microposts do
member do
post :vote_up, :unvote
end
end
resources :microposts do
member do
post :upview
end
end
resources :microposts do
resources :comments
end
get "schools/:page/mostrecent" => "schools#mostrecent", :as => "mostrecent_schools"
root to: "pages#index"
From what I can understand, Your routes.rb should look something like this
My final try
Change your routes.rb to this
get "schools/mostrecent/new/:page" => "schools#mostrecent", :as => "mostrecent_schools"
and in your controller edit this line. If this dosen't work then i give up
#school = School.find_by_slug(request.referer.gsub('http://localhost:3000/','')).params[:page]
Although this is not the restful way of doing stuff and as far as I know since users belong to schools and microposts belong to users you shouldn't define schools microposts and users as simple :resources.
Refer to [Rails Routing Guide ](Refer to http://guides.rubyonrails.org/routing.html)for more details.

Rails 3 routing from root show

Currently
Project101::Application.routes.draw do
match '/:id' => 'companies#show'
resources :companies do
resources :customers
resources :users
resources :categories
resources :addresses
end
devise_for :users
resources :users, :controller => "users"
root :to => "companies#index"
end
Everything belongs to a company. Trying to create routes like www.example.com/:id/customers where :id is always the company id.
At the moment www.example.com/:id works but all url's are generated as /companies/:id/cusotmers.
Saw Rails 3 Routing Resources with Variable Namespace.
Is this the right way of doing this?
EDIT
Kept :as => :company to help generate the URL's, Links, etc a little easier for me. Sure others could do cleaner or better method. Also had to manually create the edit, destroy, new with different urls so I could use them in links if user was admin.
Project101::Application.routes.draw do
match '/' => 'companies#index'
match '/companies' => 'companies#index'
match '/:company_id' => 'companies#show', :as => :show_company
match '/companies/:id/edit' => 'companies#edit', :as => :edit_company
match '/companies/:id/new' => 'companies#new', :as => :new_company
match '/companies/:id/destroy' => 'companies#destroy', :as => :delete_company
scope '/:company_id', :as => :company do
resources :customers
resources :users
resources :categories
resources :services
resources :addresses
end
devise_for :users
resources :users, :controller => "users"
root :to => "companies#index"
end
Then just used basic nested_resources for links, controllers and forms.
class ApplicationController < ActionController::Base
protect_from_forgery
helper_method :current_company
def current_company
if params[:company_id] != nil
#current_company ||= Company.find(params[:company_id])
else
#current_company = nil
end
return #current_company
end
end
Basic links
<%= link_to "Customers", company_customers_path(current_company) %>
links for specific customer
<%= link_to #customer.name, edit_company_customer_path(current_company, #customer) %>
Controllers look like
class CustomersController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource
def new
#company = current_company
#customer = #company.customers.new
end
def create
#customer = Customer.new(params[:customer])
if #customer.save
flash[:notice] = "Successfully created customer."
redirect_to company_customer_path(current_company, #customer)
else
render :action => 'new'
end
end
end
And finally my forms look like
<%= form_for [#company, #customer] do |f| %>
<%= f.error_messages %>
....
<% end %>
Yes, if you always want the routes to begin with the company id you can wrap them in a scope like this:
scope ":company_id" do
resources :customers
resources :users
resources :categories
resources :addresses
end

Resources