I'm trying to get a link on an articles show page so that when a user clicks write new review it takes them to the link
/comic_reviews/'the article they want to comment on'/reviews/new
where they will be directed to the new reviews page
how can i accomplish this with
In your routes file you would specify a route like this
match '/comic_reviews/:comic_name/reviews/new' => 'reviews#new', via: :get
Then in your reviews controller you would need something like this
reviews_controller.rb
class ReviewsController < ApplicationController
def new
#comic = Commic.find_by_name(params[:comic_name])
if #comic
#review = #comic.reviews.build
render 'new'
else
#Render some error page since comic was not found
end
end
end
You will then have access to #comic and #review in your reviews/new view so you could build a form that just makes a post to create a review and allows you to store it. This should get you going.
Edit
In your new view you'd need to have a form that looks something like this
<%= form_for #review do |f| %>
<%= f.label :some_attribute %>:
<%= f.text_field :some_attribute %><br />
<%= f.submit %>
<% end %>
This will be expecting you have a route to create a review in your routes file and an action in your ReviewsController.
If you are struggling with such topics I suggest you read over this excellent tutorial
http://ruby.railstutorial.org/ruby-on-rails-tutorial-book
Or just read through the documentation for Rails API which will give you pretty accurate examples.
You can do this via routes
resources :comic_reviews do
resources :reviews
#probably_some_other_route_here
end
And with restful pattern it will be easy to achieve whatever you want
controller
Someclass < Someotherclass
#some your code
def new
#instance_var = Your_model.new
end
def create
#instance_var = Your_model.new(params[:some_name_here])
if #instance_var.save
redirect_to somewhere
else
render 'new'
end
end
end
Also you'll need form, but i dont think that will cause any troubles
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.
In my rails app I'm trying to use a form partial to display the same quiz on the new and edit views. I can see the new view page, but when I hit <%= f.submit "Submit Answers" %> I get an error saying No route matches [POST] "/flex_quiz/new".
Here is the form for line in my partial:
<%= form_for #flex_quiz, url: url do |f| %>
And here's how the locals stand in my new view:
<%= render partial: "quiz", locals: { url: new_flex_quiz_path, method: :post } %>
And my edit view:
<%= render "quiz", url: edit_flex_quiz_path(#flex_quiz), method: :put %>
Here are the route paths:
Prefix Verb URI Pattern Controller#Action
...
flex_quiz_index GET /flex_quiz(.:format) flex_quiz#index
POST /flex_quiz(.:format) flex_quiz#create
new_flex_quiz GET /flex_quiz/new(.:format) flex_quiz#new
edit_flex_quiz GET /flex_quiz/:id/edit(.:format) flex_quiz#edit
flex_quiz GET /flex_quiz/:id(.:format) flex_quiz#show
PATCH /flex_quiz/:id(.:format) flex_quiz#update
PUT /flex_quiz/:id(.:format) flex_quiz#update
DELETE /flex_quiz/:id(.:format) flex_quiz#destroy
Can anyone suggest how to fix this? I have looked at several similar posts (like this and this) but since I'm using partials the solution here is going to have to be a bit different.
EDIT
Here are my definitions in my flex_quiz_controller:
class FlexQuizController < ApplicationController
before_action :require_sign_in
def show
#flex_quiz = FlexQuiz.find(params[:id])
end
def new
#flex_quiz = current_user.build_flex_quiz
end
def create
#flex_quiz = FlexQuiz.new
#flex_quiz.flex01 = params[:flex_quiz][:flex01]
#flex_quiz.flex02 = params[:flex_quiz][:flex02]
#flex_quiz.flex03 = params[:flex_quiz][:flex03]
#flex_quiz.flex04 = params[:flex_quiz][:flex04]
#flex_quiz.flex05 = params[:flex_quiz][:flex05]
#flex_quiz.flex06 = params[:flex_quiz][:flex06]
#flex_quiz.flex07 = params[:flex_quiz][:flex07]
#flex_quiz.flex08 = params[:flex_quiz][:flex08]
#flex_quiz.flex09 = params[:flex_quiz][:flex09]
#flex_quiz.flex10 = params[:flex_quiz][:flex10]
#flex_quiz.user = current_user
if #flex_quiz.save
flash[:notice] = "Quiz results saved successfully."
redirect_to user_path(current_user)
else
flash[:alert] = "Sorry, your quiz results failed to save."
redirect_to welcome_index_path
end
end
def edit
#flex_quiz = FlexQuiz.find(params[:id])
end
def update
#flex_quiz = FlexQuiz.find(params[:id])
#flex_quiz.assign_attributes(flex_quiz_params)
if #flex_quiz.save
flash[:notice] = "Post was updated successfully."
redirect_to user_path(current_user)
else
flash.now[:alert] = "There was an error saving the post. Please try again."
redirect_to welcome_index_path
end
end
private
def flex_quiz_params
params.require(:flex_quiz).permit(:flex01, :flex02, :flex03, :flex04, :flex05, :flex06, :flex07, :flex08, :flex09, :flex10)
end
end
If you want to create new flex_quiz objects, then you're going to want to POST to flex_quiz_index_path.
Notice in your route paths, if you look at new_flex_quiz, the HTTP verb is a GET.
It may be slightly unintuitive, but the new action is actually a GET request.
The action in which the object is supposed to be created in is the create action.
So to solve your problem this should do the trick:
<%= render partial: "quiz", locals: { url: flex_quiz_index_path, method: :post } %>
EDIT:
Instead of defining locals, you can simply define your forms in form_for as such:
You will also have to define #flex_quiz in your controller actions as well (in your case new and edit) form_for will automatically infer the appropriate URL.
From documentation:
However, further simplification is possible if the record passed to
form_for is a resource, i.e. it corresponds to a set of RESTful
routes, e.g. defined using the resources method in config/routes.rb.
In this case Rails will simply infer the appropriate URL from the
record itself.
You'll also need to change the naming from singular form to plural.
The rails to do resuable forms is:
app/views/flex_quiz/_form.html.erb:
<%= form_for(#flex_quiz) do |f| %>
# ...
<% end %>
app/views/flex_quiz/new.erb:
<h1>Create a new quiz</h1>
<%= render 'form' %>
app/views/flex_quiz/edit.erb:
<h1>Edit a quiz</h1>
<%= render 'form' %>
While using locals can often be a good idea its not needed here. Note we just pass the resource and not a URL to form_for - that is convention over configuration in action and is what makes Rails awesome.
Rails figures out all by itself what URL to use for the action attribute and what method to use based on if the resource has been saved.
However for this to work you to actually follow the conventions. Make sure you are using the proper plural forms (the plural of quiz is quizzes):
resources :flex_quizzes
class FlexQuizzesController < ApplicationController
end
Unfortunately when it comes to rest of your setup you need to revisit the drawing board. Its not very realistic to think that you can do this with a single model. You would usually have several models with relations:
class Quiz
has_many :questions
end
class Question
belongs_to :quiz
has_many :answers
end
class Answer
belongs_to :question
end
class UserQuiz
belongs_to :user
belongs_to :quiz
end
class UserAnswer
belongs_to :question
belongs_to :answer
end
You would use one or several controllers to let admins create the quizes and a separate controller to let users answer the quiz. Its a quite common domain so you should be able to find plenty of examples.
So as it stands I have a form partial which starts off as:
<%= form_for(#merchandise) do |f| %>
It works perfectly for editing the data that I have already assigned in the rails console. When I try to use it for a "new" form that creates new merchandise (in this case the singular form of merchandise, I don't have nested resources, multiple models etc.), I get a no Method error that states
"undefined method 'merchandises_path' for #<#<Class:0x64eaef0>:0x95d2370>".
When I explicitly state the URL in the form_for method:
<%= form_for(#merchandise url:new_merchandise_path) do |f| %>
I get it to open and I finally have access to the form, however in this case I get a routing error that states
"No route matches [POST] "merchandise/new"".
I decided to write out that route in my routes file which previously just had:
root "merchandise#index" resources :merchandise
After I add the route it literally does nothing. I click submit and it takes me to the form but there is no new data in the database. I am at a complete loss and have been at this for hours googling and stack overflowing and I just don't know what to do anymore. All help is seriously appreciated. I'm adding a pastebin with all my code in the following url:
http://pastebin.com/HDJdTMDt
I have two options for you to fix it:
Option 1:
Please try to do this for best practice in Rails:
routes.rb
change your routes use plural
resources :merchandises
merchandises_controller.rb
Rename your file controller and class into MerchandisesController
class MerchandisesController < ApplicationController
def index
#merchandise = Merchandise.all
end
def new
#merchandise = Merchandise.new
end
def create
#merchandise = Merchandise.new(merchandise_params)
if #merchandise.save
redirect_to merchandises_path
else
render :new
end
end
def show
#merchandise = Merchandise.find(params[:id])
end
def edit
#merchandise = Merchandise.find(params[:id])
end
def update
#merchandise = Merchandise.find(params[:id])
if #merchandise.update(merchandise_params)
redirect_to #merchandise, notice: "The movie was updated"
else
render :edit
end
end
def merchandise_params
params.require(:merchandise).permit(:shipper, :cosignee, :country_arrival_date, :warehouse_arrival_date, :carrier, :tracking_number, :pieces, :palets, :width, :height, :length, :weight, :description, :cargo_location, :tally_number, :customs_ref_number, :released_date, :updated_by, :country_shipped_to, :country_shipped_from)
end
end
Option 2:
If you want to not change many code
/merchandise/_form.html.erb
in partial file
/merchandise/new.html.erb
<%= render 'form', url: merchandise_path, method: 'post' %>
/merchandise/edit.html.erb
<%= render 'form', url: category_path(#merchendise.id), method: 'put' %>
In the rails guides tutorial creating a blog app after we create the rails app and create a resources in the routes then we start working on a form_for for creating a posts title and text in the guide it tells me that we need to add this line <%= form_for :post, url: posts_path do |f| %>
the posts_path helper is passed to the :url option. What Rails will do with this is that it will point the form to the create action of the current controller, the PostsController, and will send a POST request to that route.
so what am trying to understand is the passing to 'create action' you see I have a simple app where i want is when a text is entered in the title field and the submit button is entered I want it to pass to the create action where I just out put the text in the create action view or another view, the rails guide goes through teaching the 'CRUD' but I just want to understand How to build an app that doesn't use 'CRUD' for instance an app that takes an input and outputs it in another view?
my form:
<h1>Here Lets create a simple post</h1>
<%= form_for :post, url: posts_path do|f| %>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
posts controller:
class PostsController < ApplicationController
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
end
def post_params
params_require(:post).permit(:title)
end
end
create view:
<h1>THis is the post create action</h1>
<%= #post.title %>
routes:
Learnnobase::Application.routes.draw do
resources :posts
root "welcome#home"
end
Right now am getting an error stating uninitialized constant PostsController::Post highlighting my create method? I've done so many rails app tutorials using 'CRUD' I really wanna learn building a simple app without using 'CRUD', I was trying to experiment with this app even though I do use the create action of "CRUD".
We generally use Rails to build database-backed applications, but for learning purposes, you can do it this way.
The problem you are facing here is: You are tyring to create an object of the Post class, that will be the model in the example you are referring to. The error comes up since you have not created the Post model.
To meet your requirement you can make your create action be:
def create
#post = post_params #this will be a hash
end
Then change your view to:
<h1>THis is the post create action</h1>
<%= #post[:title] %>
Since you have started with rails, I would ask you how did your posts/new page load with #post = Post.new in posts/new action when you do not have post model file and class?
It is not possible. Second, with what Manoj Monga has suggested you to use params by assigning it to an instance variable(wrong way to do so with params), if you try to use create_path for posts resources which literally is '/posts' you would end up hitting posts/index action.
Rails has standard reserve action names like :index(GET, /posts), :show(GET, /posts/:id), :new(GET, /posts/new), :create(POST, /posts), :edit(GET, /posts/:id/edit), :update(PATCH, /posts/:id) You should not attempt at overriding their purpose.
What I understand that you did use post model class and loaded posts/new page, then you deleted post model class and tried with what you have asked about in your question. You should respect Rails' standards.
I am trying to get a basic form to work and am struggling because I keep getting the error
undefined method `profiles_index_path' for #<#<Class:0x4fe1ba8>:0x4fccda0>
I have checked through and can't seem to work out where I am going wrong.
In my view (new.html.erb) I have:
<%= form_for #profile do |f| %>
<%= f.text_field :name %>
<%= f.text_field :city %>
<%= f.text_field :country %>
<%= f.text_field :about %>
<%= f.submit "Create Profile" %>
<% end %>
In my profiles controller I have:
class ProfilesController < ApplicationController
def new
#title = "New Profile"
#profile = Profiles.new
end
def create
#user = current_user
#profile = #user.profiles.new(params[:profile])
if #profile.save
redirect_to profile_path, :notice => "Welcome to your new profile!"
else
render "profiles#new"
end
end
def edit
#user = current_user
#profile = #user.profiles.find(params[:id])
end
def update
#title = "Update Profile"
#user = current_user
#profile = #user.profiles.find(params[:id])
if #profile.update_attributes(params[:profile])
redirect_to profile_path
else
render action: "edit"
end
end
def index
#user = current_user
#profile = #user.profiles.all
#title = "Profile"
end
end
And finally in my profiles model I have
class Profiles < ActiveRecord::Base
belongs_to :user
end
Any help people can offer really would be much appreciated because I am stumped. :)
Sorry forgot to include routes:
controller :profiles do
get "newprofile" => "profiles#new"
get "updateprofile" => "profiles#update"
get "profile" => "profiles#home"
end
resources :profiles, :controller => 'profiles'
The problem is indeed the way you've pluralized your model name. Don't do that. It should be a Profile, not a Profiles. There my be some work around to allow you to use a plural model name, but the answer is to stick to Rails convention rather than fighting the framework. Rename your model to Profile and the url_for helpers will understand how to correctly turn a new Profile object into a /profiles URL.
If you run "rake routes" command, do "profiles_index" appear in your routes? Usually for the index page of a model, the work 'index' is left out so the route is profiles_path
You error probably comes from a view where you've used profiles_index_path instead of profiles_path
I think it's failing due to the convention not being followed with your model name.
So I think you're problem is mostly around that you aren't following the convention on the model name, which would classically be singular, since each instance represents one profile. I think the form_for helper is trying to figure out what to do with it and failing as a result. So you have two options to try and resolve. Refactor the model name to singular (I'm not clear exacly how difficult that would be) or pass the :url paramater to form_for so it knows where to post to.
<% form_for #profile, :url => path_to_create_action do |f| %>
more information here:
I'm working with Rails 5 and I got the same error and it was specific using the word Media as my model and RoR used Medium as the plural so I got different routes when executing rake routes.
What I did to fix it was:
Delete the model I just have created.
rails d scaffold Media
Edit config/initializers/inflections.rb with:
ActiveSupport::Inflector.inflections(:en) do |inflect|
# Here you can put the singular and plural form you expect
inflect.irregular 'media', 'medias'
end
Now execute the scaffold again:
rails g scaffold Media
Now you must have everything in the way you expected. Because you have overwritten the Pluralizations and Singularizations (Inflections) in Ruby on Rails.
I hope it could be useful.
Have you tried to replace your form_for tag with the following?
<%= form_for #profile, :as => :post do |f| %>
It looks like it's trying to treat it as a GET request to "/profile". And, since it is not finding the index action, it craps out. I think forcing it to do a POST will fix this issue.