This is a tough one I think. I have a comments controller, that I'd like to use for all of my other controllers: such as books, titles, etc.
The problem is, the create action in comments is:
def create
#book = Book.find(params[:book_id])
#comment = #book.comments.create!(params[:comment])
respond_to do |format|
format.html {redirect_to #book}
format.js
end
end
so how can I use the action & comments controller for titles, if its clearly using books attributes?
I'm assuming you have a polymorphic association setup on comment so it can belong to many different types of models? Take a look at this Railscasts episode which shows you how to set that up along with the controller action. Here's the key bit of code.
# comments_controller
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment])
if #comment.save
flash[:notice] = "Successfully created comment."
redirect_to :id => nil
else
render :action => 'new'
end
end
private
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
# routes.rb
map.resources :books, :has_many => :comments
map.resources :titles, :has_many => :comments
map.resources :articles, :has_many => :comments
That's something I've mulled over too. You'd have to make the create method independent of the parent, first of all.
Then you'd have a couple options:
Have a belonsg_to for every thing the comment could possibly be attached to, and selectively fill one of them out.
Have the books/titles/etc belongs_to the comment
I'm fairly new to Rails myself, so I don't know of that's the "correct way" of doing things, maybe someone else has a better solution.
Well, you can't do this generally without being specific about attribute for each of the controllers.
If you wanted to to create a general comments model for a bunch of models in your application, you'd need to pass on the model type that you're commenting to (but not the model itself), and then create a switch that would provide different behaviour based on what you pass.
def create
if params[:type]="book"
#book = Book.find(params[:book_id])
#comment = #book.comments.create!(params[:comment])
respond_to do |format|
format.html {redirect_to #book}
format.js
elsif params[:type]="title"
#title = Title.find(params[:title_id])
#comment = #title.comments.create!(params[:comment])
respond_to do |format|
format.html {redirect_to #title}
format.js
end
end
I think the resource controller is probably what you're looking for. Here's another link on the resource controller.
Related
I'm new to wicked form and I was following the railcast episode on wicked forms but I keep receiving this error "Couldn't find Company with 'id'=info". So I know that the problem is clearly in my controllers somewhere. I know it's something super simple that I'm just racking my brain on so I know you guys will be a giant help. Here is the code, any and all help appreciated!
Code for companies Controller:
def create
#company = Company.new(company_params)
respond_to do |format|
if #company.save
#object = #company.id
format.html { redirect_to(company_steps_path(#company)) }
format.json { render :show, status: :created, location: #company }
else
format.html { render :new }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
Code for company_steps Controller:
class CompanyStepsController < ApplicationController
include Wicked::Wizard
steps :info, :address, :quote
def show
#company = Company.find(params[:id])
render_wizard
end
def update
#company = Company.where(id: params[:id])
#company.attributes = params[:company]
render_wizard #company
end
end
When you use #find and the record is not found ActiveRecord raise a ActiveRecord::RecordNotFound with a message like "Couldn't find Company with id='somevalue'".
I assume your id column is of type integer and you pass a string.
In your #show method params[:id] == 'info'.
Check your link_to, redirect_to and routes.
At some point you generate this url http://localhost:3000/company_steps/info (probably in a view).
You do a GET request on it, which match GET "/company_steps/:id" company_steps#show.
The method #show is call in the controller CompanyStepsController with params[:id] == 'info'.
As we see previously you get a ActiveRecord::RecordNotFound exception because ActiveRecord can't find the record with a id 'info'.
The error is raise in your controller, but the problem is probably in your views or in a redirect. You need a id and you pass a string.
EDIT: as discussed in comments
Ok params[:id] == 'info' is generated by wicked.
They use id to control the flow of steps.
You need to use nested routes to have rails generate something like params[:company_id].
resources :companies do
resources :steps, controller: 'companies/steps'
end
So rake routes should give you:
/companies/:company_id/steps/:id
in the controller
params[:company_id] == 42
params[:id] == 'info'
https://github.com/schneems/wicked/wiki/Building-Partial-Objects-Step-by-Step
I am a beginner of Rails. I am learning rails with the book 'Beginning Rails 4' now. I want to ask you about 'parameter' passed to params method. The following is one of typical rails controllers.
class CommentsController < ApplicationController
before_action :load_article
def create
#comment = #article.comments.new(comment_params)
if #comment.save
redirect_to #article, notice: 'Thanks for your comment'
else
redirect_to #article, alert: 'Unable to add comment'
end
end
def destroy
#comment = #article.comments.find(params[:id])
#comment.destroy
redirect_to #article, notice: 'Comment Deleted'
end
private
def load_article
#article = Article.find(params[:article_id])
end
def comment_params
params.require(:comment).permit(:name, :email, :body)
end
end
Yes, this is just a typical comment controller used to create a comment attached to an article. The Comment model 'belongs to' the Article model, and the Article model 'has many' comments.
Take look at the destroy method.
def destroy
#comment = #article.comments.find(params[:id])
-- snip --
end
It finds the comment associated with the article by find(params[:id]). My question is, where on earth does params[:id] come from?
Does it come from URL? Or does rails save params hash automatically whenever any comment record is created? So we can find any comment by find(params[:id])?
The load_article method is similar.
def load_article
#article = Article.find(params[:article_id])
end
It finds an article by params[:article_id]. Where does this params[:article_id] come from? How does rails find an article by this?
params[:id] is meant to be the string that uniquely identifies a (RESTful) resource within your Rails application. It is found in the URL after the resource's name.
For example, for a resource called my_model, a GET request should correspond to a URL like myserver.com/my_model/12345, where 12345 is the params[:id] that identifies that specific instance of my_model. Analogies follow for the other HTTP requests (PUT, DELETE etc) and their RESTful counterparts.
You should read about Rails routing and its interpretation of RESTful architecture if you're still confused about these concepts and terminologies.
params[:id] does come from the URL. When you use resources in your routes file, Rails will automatically generate the standard REST routes for you. In your destroy example, that would usually be a be a request to /comments/:id using the DELETE HTTP method, in which that :id is added to the params hash, i.e. params[:id].
Building a forum in ruby for fun and to learn the language. To start this off, i understand basic constructs, but I am very new to server-side languages and am primarily a front-end developer. I am trying to extend my skills.
I don't necessarily want you to code for me (although code examples would be appreciated), but I would like you to explain to me why my code is terrible, which I'm sure it is and tell me how to fix it. Just need some help understand how to relate two models togethers and how to set up that relation in the controllers.
Thanks!
Here are my two models:
Post model:
class Post < ActiveRecord::Base
belongs_to :topic
end
Topic model:
class Topic < ActiveRecord::Base
belongs_to :user
has_many :posts
end
Now here come the controllers. These are where I am really lost. I got the topic creation working, and I tried to just copy what I did in the topic controller. I pretty much knew it wasn't going to work, but I am sorta lost. Here it is...
Topic Controller
class TopicsController < ApplicationController
def index
#topics = Topic.order("sticky desc")
end
def show
#topic = Topic.find(params[:id])
end
def new
#topic = Topic.new
end
def create
#topic = Topic.new(topic_params)
#topic.user = current_user
if #topic.save
redirect_to #topic, notice: "Created topic."
else
render :new
end
end
def edit
#topic = Topic.find(params[:id])
end
def update
#topic = Topic.find(params[:id])
if #topic.update_attributes(topic_params)
redirect_to topics_url, notice: "Updated topic."
else
render :edit
end
end
def destroy
#topic = Topic.find(params[:id])
#topic.destroy
redirect_to topics_url, notice: "Destroyed topic."
end
private
def topic_params
params.require(:topic).permit(:name, :post_content, :sticky)
end
end
Posts Controller
class PostsController < ApplicationController
def index
#posts = Post.order("sticky desc")
end
def show
#post = Post.find(params[:id])
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.user = current_user
if #post.save
redirect_to topics_url, notice: "Post created."
else
render :new
end
end
def edit
#post = Post.find(params[:id])
end
def update
if #post = Post.find(params[:id])
redirect_to topics_url, notice: "Updated post."
else
render :edit
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to topics_url, notics: "Post removed."
end
private
def post_params
params.require(:posts).permit(:content, :created_at, :updated_at)
end
end
I don't believe the views are an issue, and I will post a new question if there is once I get the controller logic figured out.
Again, any help would be appreciated. Please just no comments like, "you should really start back at the beginning", or "you aren't experienced enough, learn this first", because I know I am not experienced, hence why I am here asking you all.
You can show how you would code it, or just explain the logic that needs implemented to me, either is appreciated!
Thanks a ton everyone!
EDIT
I am getting a routing error actually. So obviously the routing is wrong, wasn't sure if it had something to do with the controller code tho: Here is the specific error. (this occurs when I try to click into a topic (I can edit and destroy topics, just not click into them)
Routing Error
No route matches {:action=>"new", :controller=>"posts"}
Try running rake routes for more information on available routes.
Here is my routes files so far:
Forum::Application.routes.draw do
get 'signup', to: 'users#new', as: 'signup'
get 'login', to: 'sessions#new', as: 'login'
get 'logout', to: 'sessions#destroy', as: 'logout'
resources :sessions
resources :topics do
resources :posts
end
resources :users
root to: 'topics#index'
end
Serve is a little Rack-based web server that makes it simple to serve ERB or HAML from any index. Serve is an optimal apparatus for building HTML models of Rails applications. Serve can likewise deal with SASS, Textile, and Markdown in the event that the suitable diamonds are introduced.
enter image description here
Each project can have a single page:
resources :project do
resource :page
end
class Project < ActiveRecord::Base
has_one :page
end
class Page < ActiveRecord::Base
belongs_to :project
end
def new
#project = Project.find(params[:project_id])
#page = #project.build_page
respond_to do |format|
format.html
end
end
def create
#project = Project.find(params[:project_id])
#page = #project.build_page(params[:page_id])
respond_to do |format|
if #page.save
format.html { redirect_to #page, :notice => 'Page was successfully created.' }
else
format.html { render action: "new" }
end
end
end
But when I go to save a page, I not only get a routing error, but it doesn't actually save to the db.
Routing Error
No route matches [POST] "/projects/2/pages"
My form action looks like this:
<%= form_for([#job, #page]) do |f| %>
Does anyone have any idea of what is going on? I kind of pieced all of this together from other SO posts, but the more I change a line here or there, I feel like I'm getting further from a working solution. For example, if I change the form action to be:
<%= form_for #page, url: job_page_path(#job) do |f| %>
Everything magically works, but then the edit action is still broken. What basic concept am I butchering?
Thanks!
--Mark
you have a typo:
resource :page
should be
resources :page
(notice the s)
resource (singular) is actually quite a different method that builds a different set of routes. See the docs for more info.
UPDATE / ERRATUM
sorry, i've read your question too fast. you should take a look at Ruby on rails: singular resource and form_for - it seems that form_for does not know how to properly handle singular resources.
Someone here on SO suggests a quick fix for this : nested form_for singular resource
I have a rails 3.2 project.
There are a bid object and i want the user to be able to accept this bid!
How can i do this?
My first thought is about to make a new method on bids controller and in the method i have to update the accept boolean of bid.Something like that?
def accept
#bid = Bid.find(params[:id])
#bid.subject ='accept!!!!'
flash[:notice] = "Successfully destroyed post."
respond_to do |format|
format.html { redirect_to "/mybids" }
format.json { head :no_content }
end
end
You're question is a little vague, because it's not clear what a bid is attached to, or what the other models are in your app, since you don't say.
However, let's say that this is an auction site, and auctions have bids. When a bid is accepted
All other bids on that auction are destroyed
The bid that was accepted has it's accepted boolean field set to true.
If that is close to what you're trying to do, then the code below should accomplish that.
in app/controllers/bids_controller.rb
# PUT /bids/:id/accept
def BidsController < ApplicationController
def accept
#bid = Bid.find(params[:id])
#bid.update_attribute(:accepted, true)
#bid.auction.bids.each do |rejected_bid|
rejected_bid.destroy unless rejected_bid == #bid # destroys all be the accepted bid
end
flash[:notice] = "Bid accepted."
respond_to do |format|
format.html { redirect_to "/mybids" }
format.json { head :no_content }
end
end
end
Then you need to add a route for this action to your config/routes.rb file. Something like...
resources :bids do
put :accept, :on => :member
end
Form the view, you would link to this route like this:
link_to "accept", accept_bid_path(#bid)
And if you call rake routes from your command line, you should see an entry that looks like this:
accept_bid PUT /bids/:id/accept(.format) {:action=>"accept", :controller=>"bids}