Have same action for before submit and after submission - ruby-on-rails

I want to know if it possible to have a same action, for example Users#connexion, and have for this a GET request which give the form for the connexion, and from the same action, a POST one for use the data send by the form.
Because for the moment I've a Users#connexion action, which connect a user, and an empty action Users#getconnect, which route to the form.
Connect Users#action
def connect
if usr = User.find_by(:student_number, params['student_number']) && usr.password == params['password']
session[:user] = usr
puts "connexion OK"
else
puts "Fail connexion"
end
respond_to do |format|
format.html { redirect_to users_url, notice: 'Connect!' }
end
end
getConnect
def getConnect
end
routes.rb
get '/connexion', to: 'users#getConnect'
post '/connexion', to: 'users#connect'
EDIT:
Okay so It was very simple, your answer work, shame on me...
def connect
if request.post?
if usr = User.find_by(:student_number, params['student_number']) && usr.password == params['password']
session[:user] = usr
puts "connexion OK"
else
puts "Fail connexion"
end
respond_to do |format|
format.html { redirect_to users_url, notice: 'Connect!' }
end
end
end
And yes thanks for the comment, effectively I don't need the "else" statement, the view is rendering automatically!

You can use:
def connect
if request.post?
#Something
else
#Something else
end
end

Related

why is this failing 'undefined method `destroy' for nil:NilClass' rspec rails

The idea of this test is to handle the event a record is not found. There for a destroy action should not take place and yet it is. I've chopped and changed it around, nut essentially the test reads right, so there must be a problem in my code.
RSpec.describe Admin::EntriesController, :type => :controller do
setup_factories
let(:model){ Photo }
let(:instance){photo}
let(:no_instances){no_photos}
let(:some_instances){some_photos}
let(:params_full_instance){params_full_photo}
let(:params_new_instance){params_new_photo}
describe "delete destroy" do
context "where the record is found" do
before do
allow(model).to receive(:where).and_return(some_instances)
allow(some_instances).to receive(:first).and_return(instance)
end
context "where the record is destroyed" do
before do
allow(instance).to receive(:destroy).and_return(true)
delete :destroy, params_id
end
sets_flash(:notice)
redirects_to('/admin/entries/rejected')
end
context "where the record is not destroyed" do
before do
allow(instance).to receive(:destroy).and_return(false)
delete :destroy, params_id
end
sets_flash(:error)
redirects_to('/admin/entries/rejected')
end
end
context "where the record is not found" do
before do
allow(model).to receive(:where).and_return(no_instances)
delete :destroy, params_id
end
sets_flash(:error)
redirects_to('/admin/entries/rejected')
end
CONTROLLER
before_action :get_entry_id, only: [:destroy, :toggle_approve_field, :toggle_reject_field]
def destroy
if #entry.nil?
flash[:error] = "object is not not found"
end
if #entry.destroy
flash[:notice] = 'blah'
respond_to do |format|
format.html { redirect_to rejected_admin_entries_path }
format.json { head :no_content }
format.js
end
else
flash[:error] = 'There was a problem fetching the record'
redirect_to rejected_admin_entries_path
end
end
def get_entry_id
if #entry.nil?
flash[:error] = "object is not not found"
end
#entry = Photo.where(id: params[:id]).first
end
I probably need a fresh pair of eyes on it. And a nice explanation as to what I am getting wrong ;)
UPDATE: expected behaviour, is, when a destroy action is made, and the record is not found, i expect to see a flash error and to be redirected.
UPDATE 2: Implemented guys code below, still receiving error
1) Admin::EntriesController for authenticated users delete destroy where the record is not found should set flash error
Failure/Error: expect(flash[method]).to_not be_nil
expected: not nil
got: nil
# -e:1:in `<main>'
2) Admin::EntriesController for authenticated users delete destroy where the record is not found should redirect to /admin/entries/rejected
Failure/Error: expect(response).to redirect_to(path)
Expected response to be a <redirect>, but was <200>
Thanks
Rico
Your problem is you are still trying #entry.destroy even if it is still nil.
def destroy
if #entry.nil?
flash[:error] = "object is not not found"
elsif #entry.destroy
flash[:notice] = 'blah'
respond_to do |format|
format.html { redirect_to rejected_admin_entries_path }
format.json { head :no_content }
format.js
end
else
flash[:error] = 'There was a problem fetching the record'
redirect_to rejected_admin_entries_path
end
end
The problem is in the destroy method. You are not calling return. This should work:
def destroy
if #entry.nil?
flash[:error] = "object is not not found"
return
end
if #entry.destroy
flash[:notice] = 'blah'
respond_to do |format|
format.html { redirect_to rejected_admin_entries_path }
format.json { head :no_content }
format.js
end
else
flash[:error] = 'There was a problem fetching the record'
redirect_to rejected_admin_entries_path
end
end
Anyway this code is sub-optimal. You should find the #entry in a before_filter aspect and return a 404 if is not found.
E.g.,
before_filter :find_entry
...
def find_entry
#entry = Entry.find(params[:id])
end

Issue with before_filter

Please help me try and understand what is happening here:
I need to approve a nested snippet but when I do it says it cannot find book. I think it may be an issue with the routes because the URL in the browser doesn't match the rake routes.
If someone could hold my hand and explain this as you would to a child :)
Couldn't find Book without an ID
Below is the controller with snippets#approve and the before_filter.
class SnippetsController < ApplicationController
before_filter :authenticate_user!
before_filter :find_book
def create
#raise params.inspect
#snippet = #book.snippets.create(params[:snippet])
#snippet.user = current_user
if #snippet.save
redirect_to #book
flash[:success] = "Snippet submitted and awaiting approval."
else
flash[:base] = "Someone else has submitted a snippet, please try again later"
redirect_to #book
end
end
def approve
#raise params.inspect
#snippet = #book.snippets.find(params[:id])
#snippet.update_attribute(:approved, true)
redirect_to admins_path
end
def edit
#snippet = #book.snippets.find(params[:id])
end
def update
#snippet = #book.snippets.find(params[:id])
respond_to do |format|
if #snippet.update_attributes(params[:snippet])
format.html { redirect_to #book, notice: 'Comment was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
private
def find_book
#raise params.inspect
#book = Book.find(params[:book_id])
end
end
Now I understand that since I'm doing a post my rake routes says this.
/books/:book_id/snippets/:id(.:format)
Here is the routes for the custom route:
active_snippet POST /snippets/:id/activate(.:format)
This is my custom routes for book && snippet :approval
post "books/:id/activate" => "books#approve", :as => "active_book"
post "snippets/:id/activate" => "snippets#approve", :as => "active_snippet"
I've currently got this in my browser ../snippets/2/activate
Erm.... Not sure if I'm thinking correctly.
You're sending a POST request to snippets/:id/activate which calls snippets#approve.
There is a before_filter on the entire SnippetsController that calls find_book which executes #book = Book.find(params[:book_id]). Because your path is snippets/:id/activate, params[:book_id] is nil and hence you are getting that error.
You need to either change your snippets#approve path to include the book_id, or pass the book_id as a POST param so that your before filter has access to it.

Rails Optional Sign Up - Changing Params Before Saving

I'm developing an application with optional sign up. I want to allow users, with and without accounts, to be able to add links. How could I assign a user's session[user_id] to the user_id column of Link if they're signed in when creating a link?
Current code: user_id remains nil in either case
def create
#link = Link.new(params[:link])
if #link.save
flash[:notice] = "The link was successfully added"
redirect_to :action => :hot
else
redirect_to :action => :new
end
end
I'm imagining something like this..
def create
if session[:user_id]
##link equals new link params with user_id = session[:user_id]
else
#link = Link.new(params[:link])
end
if #link.save
flash[:notice] = "The link was successfully added"
redirect_to :action => :hot
else
redirect_to :action => :new
end
end
def create
#link = Link.new params[:link]
#link.user_id = session[:user_id] if session[:user_id]
if #link.save
redirect_to { action: 'hot' }, notice: 'The link was successfully added'
else
render :new
end
end
The link will be saved with params[:link] even if the user isn't logged-in.
Be cautious to use render, not redirect_to, when a validation fails (see if you want http://guides.rubyonrails.org/action_controller_overview.html)

How to show errors for two objects and don't save unless both are valid

I have a form for two object User Board
Here is my controller:
def create
#board = Board.new(params[:board])
#user = User.new(params[:user])
respond_to do |format|
if (#user.save and #board.save)
format.js {redirect_to some_path}
else
format.js {render :action => "new" }
end
end
end
I don't want to save either one unless both are valid. And I want to show the error messages for both at one time on the form.
I have tried all types of combinations of '&&' '&' 'and' but they don't give me the result I want. They show the errors of one object while saving the other.
How can I do this properly?
&& doesn't work like && in Linux.
You have two alternatives. You can check whether the records are valid?, then perform the save.
def create
#board = Board.new(params[:board])
#user = User.new(params[:user])
respond_to do |format|
if #user.valid? && #board.valid?
#user.save!
#board.save!
format.js { redirect_to some_path }
else
# do something with #errors.
# You check the existence of errors with
# #user.errors.any?
# #board.errors.any?
# and you access the errors with
# #user.errors
# #board.errors
format.js { render :action => "new" }
end
end
end
or if your database supports transactions, use transactions.
def create
#board = Board.new(params[:board])
#user = User.new(params[:user])
respond_to do |format|
begin
transaction { #user.save! && #board.save! }
format.js { redirect_to some_path }
rescue ActiveRecord::RecordInvalid
format.js { redirect_to some_path }
end
end
end
Personally, I would check for valid?.
If you look in the source code of the save method of ActiveRecord you see:
def save(options={})
perform_validations(options) ? super : false
end
What you want to do, is running the perform_validations manually before calling save. For this, you can use the valid? method from ActiveResource. You can find the documentation here:
http://api.rubyonrails.org/classes/ActiveRecord/Validations.html#method-i-valid-3F

Why redirect_to in around_filter or after_filter won't work?

How to make redirect_to works in those filters?
I'm trying to change
def start
....
redirect_to index
end
def end
...
redirect_to index
end
to
around_filter :around
def around
...
yield
redirect_to index
end
def start
..
end
def stop
...
end
After the action is complete it renders the template automatically, thus you cannot render / redirect after the request is complete. You could solve this by putting the redirect_to at the end of the actions that you need it for. This is not what around_filters were designed to do.
Presumably, your actions already have a redirect_to or render call. You cannot call these methods twice per request.
You can change response.location, which has the same effect as calling redirect_to. An example with an after_filter (the same could be done with around):
after_filter :different_redirect, only:[:create]
def different_redirect
if self.status == 302
response.location = other_thing_path
end
end
def create
#my_thing = MyThing.new(params[:my_thing])
respond_to do |format|
if #my_thing.save
format.html { redirect_to(my_things_path) }
else
format.html { render :action => "new" }
end
end
end

Resources