How to get object from database when user submits specific key. Rails - ruby

The procedure follows:
The user fills in an ID, then check if the ID exists in the database. If it exists, create an object then redirect to its show page.
# peoples_controller.rb
class PeopleController < ApplicationController
def validate
#person = Person.find(params[:identity])
if not #person.blank?
redirect_to person_path(#person)
else
flash.now[:error] = "Unique identity does not exist"
render 'index'
end
end
end
# routes.rb
root 'people#index'
resources :people
match 'validate', to: 'people#validate', :via => 'get'
# index.html.erb
<%= form_for validate_path, method: :get do |f| %>
<%= f.text_field :identity, class: 'form-control', placeholder: 'Enter Unique ID' %>
<%= f.submit "Validate", class: "btn btn-block" %>
<% end %>
Database table :people
So when I fill in the form at index.html.erb and click the submit i.e validate,
the URL changes from http://localhost:3000 to http://localhost:3000/?%2Fvalidate%5Bidentity%5D=100&commit=Validate.
Expectations: Go to show view, render show.html.erb
Here are the logs
Started GET "/?%2Fvalidate%5Bidentity%5D=100&commit=Validate" for ::1 at 2021-04-20 16:53:42 +0800
Processing by PeopleController#index as HTML
Parameters: {"/validate"=>{"identity"=>"100"}, "commit"=>"Validate"}
Rendering layout layouts/application.html.erb
Rendering people/index.html.erb within layouts/application
Rendered people/index.html.erb within layouts/application (Duration: 0.7ms | Allocations: 744)
[Webpacker] Everything's up-to-date. Nothing to do
Rendered shared/_notices.html.erb (Duration: 0.1ms | Allocations: 55)
Rendered layout layouts/application.html.erb (Duration: 8.0ms | Allocations: 4119)
Completed 200 OK in 10ms (Views: 9.0ms | ActiveRecord: 0.0ms | Allocations: 4565)

Finally solved it. Use form_with instead of form_for
# index.html.erb
<%= form_with url: validate_path, method: :get do |f| %>
...
<% end %>

Related

Missing Params on Post in Rails?

I'm learning Ruby on Rails at the moment and we're making a blog app to learn about crud actions and such and I'm stuck on this create method in my controller not working as it does in the course. I'm having trouble the create method in this controller:
class ArticlesController < ApplicationController
def show
#article = Article.find(params[:id])
end
def index
#articles = Article.all
end
def new
end
def create
#article = Article.new(params.require(:article).permit(:title, :description))
#article.save
redirect_to #article
end
end
I get this error when trying to create an article:
ActionController::ParameterMissing in ArticlesController#create
param is missing or the value is empty: article
It seems to be getting hung up on the first line of the create method but I'm not sure why it doesn't think there's an article... Here's my new article view as well for further reference:
<h1>Create a new Article</h1>
<%= form_with scope: #article, url: articles_path, local: true do |f| %>
<p>
<%= f.label :title %><br/>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %><br/>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
Check whether your parameters coming under hash with key article like this -
{"article"=>{params}}
Also initiate Article object in new action.
You can redefine the params to permit like this:
in controller new method create object
#article = Article.new
and in form HTML add one more option use method: "post"

Ajax and Ruby on Rails with local variable?

I really don't get how to use Ajax with Ruby on Rails. I must be missing something simple.
What I want to do is to ask the user to select a date, and then make a table of documents appear, but only with the selected date (Date is an attribute of Document).
My idea is to create a local variable witch is not in my database, store the selected date in it, and then create a loop in my view saying for example #document.where(:date = date).each...
In app/controllers/documents_controller.rb, I have :
class DocumentsController < ApplicationController
def information
#documents = Document.all
#date = params[:date]
respond_to do |format|
format.html # index.html.erb
format.js{}
format.json { render json: #documents}
end
end
end
And in app/views/documents/_information.js.erb, I have:
<%= form_tag(document, :remote => true) do %>
<%= label_tag(:date, "The selected date is:") %>
<%= text_field_tag(:date) %>
<%= submit_tag %>
<% end %>
In the end, I have a field where the user puts his date, but the submit button doesn't do anything.
What do I miss ?
As discussed you need to change the flow of your app.Lets go through steps one by one
a. create your input field where you are selecting your date field. You already have your form for that
<%= form_tag(you_path_for_information_method, :remote => true) do %>
<%= label_tag(:date, "The selected date is:") %>
<%= text_field_tag(:date) %>
<%= label_tag(:portfolio, "Add portfolio") %>
<%= text_field_tag(:portfolio) %>
<%= submit_tag %>
<% end %>
In controller
def information
#documents = Document.all
#date = params[:date]
#portfolio = Portfolio.find(params[:portfolio])
respond_to do |format|
format.js{}
end
end
In your information.js.erb you can have:
$("#some_id_of_parent").html("<%=j render partial: "your_partial", locals: {portfolio: #portfolio} %>")

How to call an `f.action` to a custom :delete callback in an Active Admin form

In order to remove (paperclip) images from my objects, I have a custom callback (and route) defined:
ActiveAdmin.register Camping do
#...
member_action :destroy_image, :method => :delete do
camping = Camping.find(params[:id])
camping.image.destroy
redirect_to({:action => :show}, :notice => "Image deleted")
end
end
This works as expected; trough a named route destroy_image_admin_camping => /admin/campings/:id/destroy_image.
The problem is that I cannot find how to add this to the form:
ActiveAdmin.register Camping do
form do |f|
f.inputs "Camping" do
f.input :name
f.input :image
f.action :delete_image, :url => destroy_image_admin_camping_path(#camping.id), :button_html => { :method => :delete }
f.input :description
end
f.actions
end
#...
end
More detailed: I don't know how to pass the "id of the current item we are editing" into destroy_image_admin_camping_path; #camping is nil, f.camping not defined and so I don't know how to pass the item in there.
Is this the right approach? I prefer this "ajax-ish" interface over a more common checkbox-that-deletes-images-on-update, but I am not sure if this will work at all.
There's a few questions here, I'll try to address them all.
How to access the "id of the current item we are editing"
You are pretty close in looking for f.camping. What you want is f.object, so:
destroy_image_admin_camping_path(f.object.id).
NOTE: f.object.id will be nil when it's a new form (as opposed to an edit form), you'll want to check for that with unless f.object.new_record?
"Is this the right approach?"
I'm not sure, really. To me it seems like making requests without actually saving the currently rendered form could create complications, but it might turn out to be a better interface. Anyway, if you want to do the checkbox-that-deletes-images-on-update, this should help you out: Rails Paperclip how to delete attachment?.
However, if you want the ajax-ish approach I think you'll want an <a> tag styled as a button. The problem with actually using a button is that you don't want to submit the form.
Here's an example:
f.inputs do
link_to 'Delete Image', delete_image_admin_camping_path(f.object.id), class: 'button', remote: true, method: :delete
end
remote: true will make it an ajax request and ActiveAdmin gives you a pretty reasonable button class for <a> tags. Updating the interface based on success / failure is left as an exercise to the reader.
Also, you'll probably want to use erb templates for this instead of the Active Admin DSL (see http://activeadmin.info/docs/5-forms.html at the bottom).
Like this:
# app/views/admin/campings/_form.html.erb
<%= semantic_form_for [:admin, #post] do |f| %>
<%= f.inputs do %>
<%= f.input :name %>
<%= f.input :image %>
<%# Actually, you might want to check for presence of the image, I don't know Paperclip well enough to demonstrate that though %>
<% unless f.object.new_record? %>
<%= image_tag f.object.image_url %>
<%= link_to 'Delete Image', delete_image_admin_camping_path(f.object.id), class: 'button', remote: true, method: :delete %>
<% end %>
...
<% end %>
<%= f.actions %>
<% end %>

Rails 3.1 Ajax forms don't show validation

I'm using updated pre Ruby on Rails on Ruby 1.9.2 (with rvm), and made a new test application with
$ rails generate scaffold Project name:string
and
class Project < ActiveRecord::Base
validates_presence_of :name
end
I change
<%= form_for #project do |f| %>
to
<%= form_for #project, :remote => true do |f| %>
I can now still (without any changes in the controller) add new items to the project. If I try to add with empty in the name field, it will not add anything (validates_presence_of :name stops this), but I don't get any validation error messages. I have tried the same on an application converted from 3.0 I'm working on with same results. Here I had:
class KursController < ApplicationController
# GET /kurs
# GET /kurs.xml
respond_to :js, :html
and:
def update
#kur = Kur.find(params[:id])
#kur.update_attributes(params[:kur])
flash[:notice] = "Lagret" if #kur.save
respond_with( #kur, :layout => !request.xhr? )
end
In 3.1 I get no validation error messages. Is this because of a bug in Ruby on Rails 3.1 or something I should do different?
You are missing to call these errors. Do something like this:
<%= form_for #project do |f| %>
<%= render :partial => 'my_error_messages_for', :locals => {:collection => #project} %>
In "_my_error_messages_for.html.erb":
<% if collection.errors.any? %>
<ul>
<% collection.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
You can create a helper for this work.
I don't believe that Ruby on Rails will automatically include the partial that you've requested. You'll need to add some JavaScript code to get it to work correctly. Something like this I imagine:
// Application.js
$("form").bind("ajax:success", function (event, data, status, xhr) {
$(event.target).replaceWith(data);
});

Rails3 routing error with ajax

UPDATED CODE at the bottom
I am creating a story voting app via Simply Rails 2 book. I am getting this error when I click the button to vote up a story:
No route matches "/stories/4-pure-css-icons-showcase"
My routing file looks like this:
Shovell::Application.routes.draw do
get "votes/create"
root :to => "stories#index"
resources :stories do
resources :votes
end
end
votes_controller.rb:
class VotesController < ApplicationController
def create
#story = Story.find(params[:story_id])
#story.votes.create
end
end
create.rsj :
page.replace_html 'vote_score', "Score: #{#story.votes.size}"
page[:vote_score].visual_effect :highlight
show.html.erb:
<h2>
<span id="vote_score">
Score: <%= #story.votes.size %>
</span>
<%= #story.name %>
</h2>
<p>
<%= link_to #story.link, #story.link %>
</p>
<div id="vote_form">
<%= form_tag :url => story_votes_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
</div>
story.rb :
class Story < ActiveRecord::Base
validates_presence_of :name, :link
has_many :votes
def to_param
"#{id}-#{name.gsub(/\W/, '-').downcase}"
end
end
I've been working through a number of other errors before this having to do with deprecated code and so forth, so I feel somewhat lost at the moment. It seems like it should just be a routing a issue, but since I've been working through AJAX errors that also have to do with the vote function I wanted to post those files just in case it was more than routing.
It says no route matches "/stories/4-pure-css-icons-showcase" but when I visit "/stories" (my root) and click on the link to take me to "/stories/4-pure-css-icons-showcase" it works fine, however after clicking on the vote button I get this error. As you could probably tell after reading the code, it is suppose to update the vote count and do a :highlight via ajax.
UPDATE:
Changed code (all changes are per Sam's advice):
routes:
Shovell::Application.routes.draw do
resources :votes
root :to => "stories#index"
resources :stories do
resources :votes
end
show.html.erb:
<div id="vote_form">
<%= form_tag :url => new_story_vote_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
</div>
votes_controller.rb
class VotesController < ApplicationController
def create
#story = Story.find(params[:story_id])
#story.votes.create
respond_to do |format|
format.html
format.js
end
end
The problem is still exactly the same, but I think (read: hope) we are making progress!
The scenario: My index (/stories) page randomly displays a story from the database, when you click the link it takes you to the story's internal page (ex. /stories/2-sitepoint-forums) on this page it displays the number of votes the story has and has a button to vote for it. When you click the vote button it is suppose to use ajax to update the #story.vote.size and use a :highlight visual effect. However, the problem is that when you click the vote button the page changes to a "Routing Error" page which displays:
No route matches "/stories/2-sitepoint-forums"
Its weird to me because you can in fact be routed to that address and you are from the link on the first page...
Here is the error in the console:
Started POST "/stories/2-sitepoint-forums?url=%2Fstories%2F2-sitepoint-forums%2F
votes%2F2-sitepoint-forums&remote=true" for 127.0.0.1 at 2010-11-08 16:30:17 -08
00
ActionController::RoutingError (No route matches "/stories/2-sitepoint-forums"):
Rendered C:/Ruby192/lib/ruby/gems/1.9.1/gems/actionpack-3.0.0.rc2/lib/action_dis
patch/middleware/templates/rescues/routing_error.erb within rescues/layout (1.0m
s)
Im not sure if this is any more telling, but I thought I'd add it incase.
New:
I have not been able to solve this problem as of yet. Because I still don't feel like I completely understand the issue I have decided to move over to the Ruby on Rails 3 Tutorial Book online and see if I can't figure it out while working through it. Since I was planning to do it next anyway (I have plans to combine both apps later) it appears now is the time.
<%= form_tag :url => new_story_vote_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
That should send it to the create action.
def create
#story = Story.find(params[:story_id])
#story.votes.create
respond_to do |format|
format.html
format.js
end
end
And that should take care of your ajax.
take this get "votes/create" out of your routes
and add this
map.resources :votes
I'm not familiar with using form_tag and :remote (as I normally just write jQuery for stuff like this) but a couple of things definitely pop out at me with what you're doing here that may help you resolve the issue.
First of all, I think you can rework the way you set up a vote and thus the way you set up the form for the vote. In the stories controller, for the show action, I'd set up the vote right away:
#vote = Vote.new(:story_id => #story.id)
This lets you set up your form as so:
= form_for(#vote), :remote => true do |f|
= hidden_field f.story_id
= submit_tag "Vote"
This is both a cleaner way of doing things, in my opinion, but also may fix the general issue you are dealing with, because you are now passing data with the form (the hidden field) in your POST request. Rails will behave unexpectedly if you perform AJAX POST requests that do not actually submit data.
In other words, your original form is likely running as an AJAX POST request but it would have worked better as an AJAX GET request, since it is not actually submitting data, it is simply "hitting" an URL.
I am not sure if you found the answer to your problem yet, but I wanted to post for others that may be looking for an answer similar to yours.
The code:
<%= form_tag :url => new_story_vote_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
will result in /stories/:story_id/votes/new url with a :post request. It won't work because the new route is a :get method request. If you wanted to go to the new method, you'll need to tell the form to use the get http method.
<%= form_tag :url => new_story_vote_path(#story), :remote => true, :html => { :method => :get } do %>
<%= submit_tag 'shove it' %>
<% end %>
However, I think that you are wanting to route to the create method in your controller. I would do something like:
<%= form_tag :url => story_votes_path(#story), :remote => true do %>
<%= submit_tag 'shove it' %>
<% end %>
This should route correctly to the create method in your VotesController.

Resources