Crud operation "Delete" don't works in my first project in ruby on rails - ruby-on-rails-4

I'm implementing in my first project the crud operation "delete", but the system take the command as a "get", whitout errors.
this is the controller:
class MoviesController < ApplicationController
def index
#movies = Movie.all
end
#GET /movies/:id
def show
id = params[:id]
#movie = Movie.find(id)
#render plain: 'show'+params[:id]
end
#POST /movies/
# skip_before_action :verify_autenticity_token:
def create
#movie = Movie.create!(params[:movie].permit(:title, :rating, :description, :realease_date))
flash[:notice] = "#{#movie.title} was successfully created."
redirect_to movies_path
end
#new
def new
end
def edit
id = params[:id]
#movie = Movie.find(id)
end
def update
id = params[:id]
#movie = Movie.find(id)
if #movie.update_attributes!(params[:movie].permit(:title,:rating,:realease_date))
flash[:notice] = "#{#movie.title} has been edited."
redirect_to movies_path
end
end
def destroy
id = params[:id]
#movie = Movie.find(id)
#movie.destroy
flash[:notice] = "#{#movie.title} has been deleted."
redirect_to movies_path
end
end
this is the view where is possible call "Delete" operation:
%h2 Details about #{#movie.title}
%ul#details
%li
Rating:
= #movie.rating
%li
Released on:
= #movie.realease_date#.strftime("%B %d, %Y")
%h3 Description:
%p#description= #movie.description
%h4 Reviews:
- if #movie.reviews.empty?
%p
No reviews for this movie...
-else
- #movie.reviews.each do |r|
- u = Moviegoer.find(r.moviegoer_id)
<b>#{r.vote}</b> (<i>#{Moviegoer.find(r.moviegoer_id).name}</i>) #{r.message} <br />
= link_to 'Add review', new_movie_review_path(#movie)
<br/><br/>
#{link_to 'Edit info', edit_movie_path(#movie)} - #{link_to 'Delete', movie_path(#movie), :method => :delete} - #{link_to 'Back to movie list', movies_path}
The problem probably is in the last line, because in server command line "Delete" isn't calls.
this is the server response (is the last GET that is execute when i press "Delete" on the browser) :
enter image description here
file routes.rb:
Rails.application.routes.draw do
resources :movies do
resources :reviews, only: [:new, :create, :destroy]
end
resources :moviegoers
root :to => redirect('/movies')
end
Result of command "rake routes":
Prefix Verb URI Pattern Controller#Action
movie_reviews POST /movies/:movie_id/reviews(.:format) reviews#create
new_movie_review GET /movies/:movie_id/reviews/new(.:format) reviews#new
movie_review DELETE /movies/:movie_id/reviews/:id(.:format) reviews#destroy
movies GET /movies(.:format) movies#index
POST /movies(.:format) movies#create
new_movie GET /movies/new(.:format) movies#new
edit_movie GET /movies/:id/edit(.:format) movies#edit
movie GET /movies/:id(.:format) movies#show
PATCH /movies/:id(.:format) movies#update
PUT /movies/:id(.:format) movies#update
DELETE /movies/:id(.:format) movies#destroy
moviegoers GET /moviegoers(.:format) moviegoers#index
POST /moviegoers(.:format) moviegoers#create
new_moviegoer GET /moviegoers/new(.:format) moviegoers#new
edit_moviegoer GET /moviegoers/:id/edit(.:format) moviegoers#edit
moviegoer GET /moviegoers/:id(.:format) moviegoers#show
PATCH /moviegoers/:id(.:format) moviegoers#update
PUT /moviegoers/:id(.:format) moviegoers#update
DELETE /moviegoers/:id(.:format) moviegoers#destroy
root GET / redirect(301, /movies)
rails_service_blob GET /rails/active_storage/blobs/:signed_id /*filename(.:format) active_storage/blobs#show
rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
rails_direct_uploads POST /rails/active_storage /direct_uploads(.:format) active_storage/direct_uploads#create

It's hard to say exactly what's going on without seeing the corresponding routes. You might try running rake routes to see what the available routes are.
Based on the comments in your controller, I'm guessing you probably have to do something like pluralize the path link_to 'Delete', movies_path(id: #movie.id), method: :delete, but that would only fix the problem if your resource routes are misconfigured.
In order for the link to work as you have it configured your route file would either have to contain resources :movies, or a specially configured route to map to the delete action.

Related

Integration testing ActionMailer and ActiveJob

In the past, Rails 3, I've integrated action mailer testing with my Cucumber/Rspec-Capybara tests like the following example. With Rails 4, using the following doesn't seem to work.
I am able to see that the job is queued using enqueued_jobs.size. How do I initiate the enqueued job to ensure that the email subject, recipient and body are correctly being generated?
app/controllers/robots_controller.rb
class MyController < ApplicationController
def create
if robot.create robot_params
RobotMailer.hello_world(robot.id).deliver_later
redirect_to robots_path, notice: 'New robot created'
else
render :new
end
end
end
spec/features/robot_spec.rb
feature 'Robots' do
scenario 'create a new robot' do
login user
visit '/robots'
click_link 'Add Robot'
fill_in 'Name', with: 'Robbie'
click_button 'Submit'
expect(page).to have_content 'New robot created'
new_robot_mail = ActionMailer::Base.deliveries.last
expect(new_robot_mail.to) eq 'myemail#robots.com'
expect(new_robot_mail.subject) eq "You've created a new robot named Robbie"
end
end
I use the rspec-activejob gem and the following code:
RSpec.configure do |config|
config.include(RSpec::ActiveJob)
# clean out the queue after each spec
config.after(:each) do
ActiveJob::Base.queue_adapter.enqueued_jobs = []
ActiveJob::Base.queue_adapter.performed_jobs = []
end
config.around :each, perform_enqueued: true do |example|
#old_perform_enqueued_jobs = ActiveJob::Base.queue_adapter.perform_enqueued_jobs
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true
example.run
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = #old_perform_enqueued_jobs
end
config.around :each, perform_enqueued_at: true do |example|
#old_perform_enqueued_at_jobs = ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs
ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true
example.run
ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = #old_perform_enqueued_at_jobs
end
end
This lets me tag features/scenarios with perform_enqueued: true if I want the jobs to actually execute.

Rails 4 - Loop through deeply nested params to prevent update of password field to blank

In an edit form, an existing password appears in the form as blank, which seems to be the default Rails behavior. I'm trying, however, to avoid the password (or in my case passwords) from being updated to blank if a new password isn't entered, similar to what is described here:
Rails Activerecord update saving unedited field as blank
The difference for me is that the password field is more deeply nested and there is more than one.
Basically what I have is a small bank transfer app where for every :transfer there are two :transfer_accounts, source and destination (transfer_accounts is a "has_many, through" join table for transfers and accounts) and both transfer accounts have an :account with a :password attribute.
My attempt was something like this at the top of the update action:
params[:transfer][:transfer_accounts_attributes].each do |k, v|
v[:account_attributes][:password].delete if v[:account_attributes][:password].empty?
end
which didn't work. Either password left blank is updated to blank.
How would I iterate through the params and prevent either or both passwords from updating if they are left blank?
Here is my controller:
class TransfersController < ApplicationController
def new
#transfer = Transfer.new
#transfer.transfer_accounts.build(account_transfer_role: 'source').build_account
#transfer.transfer_accounts.build(account_transfer_role: 'destination').build_account
#valid_banks = Bank.all.collect {|c| [c.name, c.id]} # available banks seeded in database
end
def index
#transfers = Transfer.all
end
def show
#transfer = resource
end
def create
#transfer = Transfer.new(transfer_params)
if #transfer.save
redirect_to transfers_path, notice: "Transfer Created"
else
redirect_to transfers_path, alert: "Transfer Not Created"
end
end
def edit
resource
#valid_banks = Bank.all.collect {|c| [c.name, c.id]} # available banks seeded in database
end
def update
if resource.update_attributes(transfer_params)
redirect_to transfers_path(resource), notice: "Transfer Updated"
else
redirect_to edit_transfer_path(resource), alert: "Transfer Not Updated"
end
end
def destroy
resource.destroy
end
private
def resource
#transfer ||= Transfer.find(params[:id])
end
def transfer_params
params.require(:transfer).
permit(:name, :description,
transfer_accounts_attributes:
[:id, :account_transfer_role,
account_attributes:
[:id, :bank_id, :name, :description, :user_name,
:password, :routing_number, :account_number
]
])
end
end
params[:transfer][:transfer_accounts_attributes].each do |k, v|
v[:account_attributes].delete(:password) if v[:account_attributes][:password].blank?
end
You have to call hash.delete, rather than delete the contents of the already blank value. Also .blank? is your friend, since that will take care of nil and == ''.

undefined method `model_name' for #<User:XXXXXXXX>

I have a dashboard containing 2 partials. One partial works fine and does what its suppose to (bill). The other partial is setup similar to bill but wont work(request). When I look at my log it shows that the tenant(user) is being queried, also, the 1st partial is queried but the 2nd partial doesn't query. when I went to my dashboard controller and changed the instance of the partial to (Request.new) it works but I can't seem to get it to work right thru the controller. I don't want to have the method in the model. I am using mongoid.
SO here is my render in the dashboard...
<%= render partial: "request", locals: {request: #request} %>
In the partial I have...
<%= form_for [:tenants, request] do |f| %>
And on the dashboard controller I have...
def show
#dashboard = current_tenant
#bill = current_tenant.bill || current_tenant.build_bill
#request = current_tenant.request || current_tenant.build_request
end
(if I change #request = Request.new it works fine but I know that's not right)
The bill partial works and the dashboard finds the tenant but I keep getting
"undefined method `request' for #
Any idea of what I am missing? I compared the bill controller to the request controller and I cant find any differences. When I put the Model.new into the dashboard controller it works but I know this isn't right, its as if the app wont recognize the Request controller...
The error is saying it doesn't recognize "request" method.
Also here is my controller for request...
class Tenants::RequestsController < ApplicationController
before_filter :authenticate_tenant!
def index
#requests = Request.all
end
def show
#request = Request.find(params[:id])
end
def create
if #request = current_tenant.create_request(authorization_params)
redirect_to tenants_dashboard_path, :notice => "#{request.manager_name} has been Authorized!"
else
redirect_to tenants_dashboard_path, :error => "#{request.manager_name} has NOT been Authorized, please try again."
end
end
def edit
end
def update
if current_tenant.request.update_attributes(authorization_params)
redirect_to tenants_dashboard_path, :notice => "You have approved #{request.manager_name} to review your report"
else
redirect_to tenants_dashboard_path, :notice => "#{request.manager_name} is NOT allowed to review your report"
end
end
def destroy
#request = Request.find(params[:request_id])
name = #request.name
if #request.destroy
flash[:notice] = "\"#{name}\" was successfully removed from your profile."
redirect_to #dashboard
else
flash[:error] = "There was an error deleting this managers access."
render :show
end
end
Well it looks like
current_tenant.request has an issue. That means that the method is not available. Assuming you're not trying to access the http request , then you have an issue with the request method.
So your issue is with how you defined the request method (maybe in your model). e.g. is it a class method or a instance method etc.
Without knowing your goal, that's the general answer I can give you. Creating a Request.new could be right depending on your goal, but if your goal is to call the request method, you must make it available to current_tenant
One controller shouldn't be calling your other controller as you have suggested...

Rails 4.0.4: How do I display whether or not the creation of a record was successful?

So After submitting a form for my Testimony model I get the following activity in my rails console:
Processing by TestimoniesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Y7n/+rlDoH3ys68HMOh6T6WFpAelRT18WUPstCz41vE=", "testimony"=>{"first_name"=>"bob ", "last_name"=>"balaban", "email"=>"", "contact_number"=>"", "country"=>"", "question1"=>"", "question2"=>"", "question3"=>"", "question4"=>"", "question5"=>"", "signature"=>"", "waiver"=>"0"}, "commit"=>"Save Testimony"}
(0.1ms) begin transaction
Testimony Exists (0.2ms) SELECT 1 AS one FROM "testimonies" WHERE ("testimonies"."last_name" = 'balaban' AND "testimonies"."first_name" = 'bob ' AND "testimonies"."email" = '') LIMIT 1
(0.1ms) rollback
Here is TestimoniesController
class TestimoniesController < ApplicationController
def new
end
def index
end
def show
#testimony = Testimony.find(params[:id])
end
def create
#testimony = Testimony.new(post_params)
#testimony.save
redirect_to #testimony
end
private
def post_params
params.require(:testimony).permit(:first_name, :email, :last_name, :contact_number, :country, :question1, :question2, :question3, :question4, :question5, :signature, :waiver)
end
end
Here is my Model file for Testimony.rb
class Testimony < ActiveRecord::Base
validates_presence_of :first_name, :last_name,:email, :contact_number, :country, :question1, :question2, :question3, :question4, :question5, :signature, :waiver
validates_uniqueness_of :last_name, :scope => [:first_name, :email]
end
I would like to display a message such as:
Record already exists
Or
All the fields need to be filled out
I realize this is pretty pathetic but I thought it was part of Rails magic to assert the uniqueness and presence of all of the fields of a Model at the form level, before you perform a #modelname.save. I clearly don't really understand. Thanks for your help.
if #modelname.save! failed it'll raise an exception... the exception name varies depending on the orm you might be using. but most likely it'll be ActiveModel::Validations
you can use the following pattern i myself use
#testimony.save!
redirect_to #testimony
rescue_from ActiveModel::Validations do |ex|
# here you can flash the message do what ever you want when saving fails
render json: {message: 'Record already exists', status: :unprocessable_entity
end
other solution is to use the following
if #testimony.save
redirect_to #testimony
else
render json: {message: 'Record already exists', status: :unprocessable_entity
end
[EXTRA INFO YOU CAN IGNORE :D]
I use the first solution cause i can handle exceptions in the application_controller.
for example you can add those to the application_controller to handle those failing cases
rescue_from CanCan::AccessDenied, with: :render_access_denied
rescue_from Mongoid::Errors::DocumentNotFound, with: :render_not_found
rescue_from ActionController::RoutingError, with: :render_not_found
rescue_from(ActionController::ParameterMissing) do |parameter_missing_exception|
error = {}
error[parameter_missing_exception.param] = ['parameter is required']
render_bad_request error
end
where render_XXX are methods defined in the application controller.

Rails 4 + Merit + Devise: set a badge for user after registration

I have a trouble at this situation. I followed this manual, but it don't helped me.
Here's my files:
routes.rb:
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks', registrations: 'registrations' }
merit.rb:
Merit.setup do |config|
config.checks_on_each_request = true
end
Merit::Badge.create!(
id: 1,
name: 'just-registered',
description: 'Badge for register'
)
badge_rules.rb
module Merit
class BadgeRules
include Merit::BadgeRulesMethods
def initialize
grant_on 'registrations#create', badge: 'just-registered', model_name: 'User'
end
end
end
registrations_controller.rb
def create
#user = build_resource
super
end
And if make sense - when user is registered, to merit_actions table added a new record with target_model = 'registrations', not 'users'
Can someone tell me, what i'm doing wrong ?
That's expected behavior, merit_actions is internal to the gem and saves controller_path as it's target_model attribute. It is confusing, but it shouldn't affect your application. Is the badge being granted?