Delete Record in Sinatra - ruby

I am having some trouble implementing a Delete route into Sinatra with Active Record. Here are the code details
Route
delete '/contacts/:id' do
#contact = Contact.find_by_id(params[:id])
if #contact
#contact.destroy
else
halt 404, "Contact not found"
end
View
%table.u-full-width
%thead
%tr
%th Name
%th Phone Number
%th
%tbody
- #contacts.each do |contact|
%tr
%td= contact.name
%td= contact.phone_number
%td{}
%form{:style => "margin: .75rem auto auto .25rem", :action => "/contacts/#{#contact.id}", :method => "post"}
%input{:name => "_method", :type => "hidden", :value => "DELETE"}/
%input.button#button-delete{:type => "submit", :value => "Delete"}/
Stack Error
NoMethodError at /contacts undefined method `id' for nil:NilClass
file: contacts.haml
location: block (2 levels) in singleton class
line: 55
Is the :id not passing in my views? Do I need to list contact.id in my table for it to pick up? Any help or documentation would be great.
Thanks!

The problem is that you give
#contact.id in :action => "/contacts/#{#contact.id}" which doesn't exist.
In fact you have #contacts which contains all your contacts and contact which is a single contact. It's normal that #contact is nil
Just replace it by :action => "/contacts/#{contact.id}"

Your error indicates that your local variable #contact is nil when you're attempting to render the form.
:action => "/contacts/#{#contact.id}"
are you actually passing the contact object to the contex when you are rendering this view?

If you check the error message, the error is not with how you wrote your delete action. Your delete action looks to be okay as it is. The error is in the view file corresponding to your index action.
In the index action you likely did something along the lines of: #contacts = Contact.all which sets the instance variable #contacts to a collection of contacts.
When you get to - #contacts.each do |contact| in your view, you are iterating over each element in the collection of contacts and defining a local variable called contact each time the block is run. This is what you should be referencing here :action => "/contacts/#{#contact.id}" instead of #contact.
What is happening is you are attempting to build a form that points to a delete action for each element in #contacts, but you are not actually referencing the contacts themselves, as #contact is an instance variable that has never been set. #contact is only set once you actually make a request that gets routed to the delete action.

Related

Devise not saving custom controller 'update' action for Array attribute

I've got two devise models - User and Agent - so I've got custom controllers for each.
In the Agent controller, when updating the Agent, I'm trying to pass in user_ids, which is an Array:
def account_update_params
params["agent"]["user_ids"] = params["agent"]["user_ids"].split(",")
params.require(:agent).permit(:email, :password, :password_confirmation, :current_password, {:user_ids => [:id]})
end
Before I added [:id] to user_ids, I was receiving an 'unpermitted parameter' error message. Adding [:id] solved that issue, but now my issue is that the record is not saving at all, and user_ids remains as nil.
It is being passed in the parameters though, as you can see here:
"agent"=>{"user_ids"=>"3", "email"=>"test_agent#example.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "current_password"=>"[FILTERED]"}

Cheezy's Page Object, get all text_fields defined inside Page

considering this simple Page Object:
require 'watir-webdriver'
require 'page-object'
class SomePage
include PageObject
text_field :first_name, :name => "fname"
text_field :last_name, :name => "lname"
text_field :birth_date, :name => "birthday"
button :submit, :type => "submit"
end
browser = Watir::Browser.new
page = SomePage.new(browser)
is there a way to iterate over all the text fields (or any elements) to access their "identifier" (i.e. :username, :password or :birth)?
something like:
page.text_fields.each do |text_field|
puts text_field.identifier.inspect
end
=> :first_name
=> :last_name
=> :birth_date
I'm just looking to see if I could turn this:
page.first_name = #user.first_name
page.last_name = #user.last_name
etc...
into this:
page.text_fields.each do |text_field|
attribute = text_field.attribute
text_field = #user[attribute]
end
Anybody knows what I mean?
The answers already provided definitely will suite your needs, but I would like to add one additional option that uses a feature built into the page-object gem.
It's call populate_page_with() in page_populator.rb. It's used like this so.
Start with a hash that has the element names(I use a CSV file that is loaded into a hash), as defined on your page object, in the keys. The value of the hash contains the value you wish to populate each element with.
form_data = {first_name: #user.first_name, last_name: #user.last_name, birth_date: #user.birth_date}
#page.populate_page_with form_data
That's it. The populate_page method will find the right elements on the page and populate them with whatever value you have set in your source hash. This works for checkbox, radio buttons and text.
This is a very nice time saving method that Cheezy put in for us!
Thanks Cheezy!
The names (:first_name, :last_name, :birth_date) are only used to generate the method names such as first_name=, last_name= and birth_date=. The name is not stored or retained for later use.
That said, you could iterate through the page's instance methods to find the text fields. The following text_fields method will:
Get all of the class instance methods.
Find the methods that end with "_element".
Create an array that includes the element names and element.
The page object would be:
class SomePage
include PageObject
text_field :first_name, :name => "fname"
text_field :last_name, :name => "lname"
text_field :birth_date, :name => "birthday"
button :submit, :type => "submit"
def text_fields
self.class.instance_methods(false)
.grep(/_element$/)
.map { |m|
element = self.send(m)
[m[/(.+)_element$/, 1].to_sym, element] if element.kind_of?(PageObject::Elements::TextField)
}.compact
end
end
You could then iterate through the text fields with access to their name (or attribute) and the TextField element:
page = SomePage.new(browser)
page.text_fields.each do |attribute, text_field|
text_field.value = #user[attribute]
end
I do exactly the "opposite" :
#user.each do | key, value |
unless value.empty?
browser.text_field(label: key).set value
end
end
I make the job done for the datas I have, and not the fields. It allows to test form fill with only some fields.

Active Admin Custom Method Parameter

In ActiveAdmin I'm trying to get a value from a form when I press an action_item on the dashboard, but I'm not sure exactly how to do that this is what I have so far, and it runs, but I would like to be able to pass a parameter for different method calls.
ActiveAdmin.register_page "Dashboard" do
menu :priority => 1, :label => proc{ I18n.t("active_admin.dashboard") }
page_action :scrape, :method => :post do
#The scraper works, but I don't know how to pass the info
#from the form from below into this method
# scrape = Scraper.new
# scrape.scrape
redirect_to admin_dashboard_path, :notice => "Ran the scraper!"
end
action_item do
link_to "Run Scraper", admin_dashboard_scrape_path, :method => :post
end
content :title => proc{ I18n.t("active_admin.dashboard") } do
panel "Run Course Scraper" do
para "Run the course webscraper to pull current class list and insert into the Course table in the database"
form do |f|
f.input "Session"
end
end
end
end
I want to get the input form the form where it says session to pass to the page_action :scrape somehow, any ideas?
You could to try to add controller actions to the dashboard page and add f.buttons to the form etc.
Using javascript should also work I guess.

Using Padrino form helpers and formbuilder - getting started

I've jumped into learning Ruby by going straight to Padrino with Haml.
Most of the Padrino documentation assumes a high-level of knowledge of Ruby/Sinatra etc...
I am looking for samples that I can browse to see how things work. One specific scenario is doing a simple form. On my main (index) page I want a "sign up" edit box with button.
#app.rb
...
get :index, :map => "/" do
#user = "test"
haml: index
end
get :signup, :map => "/signup" do
render :haml, "%p email:" + params[:email]
end
...
In my view:
#index.haml
...
#signup
-form_for #user, '/signup', :id => 'signup' do |f|
= f.text_field_block :email
= f.submit_block "Sign up!", :class => 'button'
...
This does not work. The render in (/signup) never does anything.
Note, I know that I need to define my model etc...; but I'm building to to that in my learning.
Instead of just telling me what I'm doing wrong here, what I'd really like is a fairly complete Padrino sample app that uses forms (the blog sample only covers a small part of Padrino's surface area).
Where can I find tons of great Padrino samples? :-)
EDIT
The answer below was helpful in pointing me at more samples. But I'm still not finding any joy with what's wrong with my code above.
I've changed this slightly in my hacking and I'm still not getting the :email param passed correctly:
#index.haml
...
#signup
- form_for :User, url(:signup, :create), :method => 'post' do |f|
= f.text_field_block :email
= f.submit_block "Sign up!"
...
#signup.rb
...
post :create do
#user = User.new(params[:email])
...
end
EDIT Added Model:
#user.rb
class User
include DataMapper::Resource
property :id, Serial
property :name, String
property :email, String
...
end
When this runs, params[:email] is always nil. I've compared this to bunches of other samples and I can't see what the heck I'm doing wrong. Help!
You can browse some example sites here: https://github.com/padrino/padrino-framework/wiki/Projects-using-Padrino
Or you can browse sources of padrinorb.com here: https://github.com/padrino/padrino-web
The best way also is to generate admin: padrino g admin where you should see how forms works.
The tag form perform by default post actions unless you specify :method => :get|:put|:delete so in your controller you must change :get into :post
post :signup, :map => "/signup" do ...
Since you are using form_for :user params are in params[:user] so to get email you need to puts params[:user][:email]

What would I need in a Rails 3 controller to process incoming emails and insert them into the database?

I'm trying to set up my RoR 3 application to receive emails and then process those emails and insert them into the database.
In my application, I have a "jobs" controller. Users can create jobs. I also have a "comments" controller. Users can create comments on jobs.
Here is (part of) what I have in my comments controller:
def new
#job = Job.find(params[:job_id])
#comment = #job.comments.build
end
def create
#job = Job.find(params[:job_id])
#comment = #job.comments.build(params[:comment])
#comment.user_id = current_user.id
#comment.commenter = current_user.login
if #comment.save
redirect_to #job
else
render :action => "new"
end
end
When users add a comment, the admin receives an email.
When admins add a comment, users receive an email.
(This is already functioning.)
I'm using Cloudmailin to help me receive incoming mail. I've set up the Cloudmailin address to point to http://myapp.com/incoming_mails.
class IncomingMailsController < ApplicationController
require 'mail'
skip_before_filter :verify_authenticity_token
def create
another_comment = Comment.create(:title =>
params[:subject], :body => params[:plain])
render :text => 'success', :status => 200 #status of 404 rejects mail
end
end
Looking at the above comment controller, it looks like I'll need the job_id, current_user.id, and current_user.login.
Here's what I am having trouble sorting out: what goes in my "incoming_mails" controller? How can I make sure that when a user responds via email that the controller in "incoming_mails" is able to find the job_id and the current_user.id (or user_id) and then insert that information into the database?
I'm thinking that I'll need to grab the user's email address and then also have the job_id in the subject line...hmmm....
Does anyone have experience setting up incoming mail processing in Rails 3?
There's a few ways to do this. A common technique is to set the from/reply_to as a custom email address that allows you to do a lookup of the original object. Something like:
class Comment < ActiveRecord::Base
belongs_to :commentable
has_many :comments, :as => :commentable
before_validation :generate_token, :on => :create
validates :token, :presence => true, :uniqueness => true
attr_accessible :token
private
def generate_token
...
end
end
Email is sent with a from/reply_to address like [token]#msg.yoursite.com
(You can also use a comments+[token_or_id]#msg.yoursite.com if you'd like - see the :disposable param supplied by cloudmailin)
class IncomingMailsController < ApplicationController
def create
#comment = Comment.find_by_token(params[:to].split('#')[0])
#comment.comments.create(:body => params[:plain])
render :text => 'success', :status => 200
end
end
If you go the [token]#msg.yoursite.com then you have to setup your dns records properly as described here.
Another option is to store content in the headers of the email. Maybe your headers would look something like this:
X-YOURAPP-OBJECT-ID = 44
X-YOURAPP-OBJECT-TYPE = Job
X-YOURAPP-TARGET-ASSOC = comments
X-YOURAPP-TARGET-ATTR = body
Then your controller would look more like this:
class IncomingMailsController < ApplicationController
def create
headers = Mail::Header.new(params[:message])
object= headers[:x_yourapp_object_type].constantize.find(headers[:x_yourapp_object_id])
object.send(headers[:x_yourapp_target_assoc]).create(headers[:x_yourapp_target_attr] => params[:plain])
render :text => 'success', :status => 200
end
end
The advantage to doing it this way is that it's completely generic. You can have comments on jobs, comments on comments, or whatever. If you create another model that you also want to allow email reply on... just update the headers and you're set. The only issue is that you have to be careful of these headers being stripped out by mail clients. Take a look at this thread for more information about that.
I'm currently using the first technique and it's working very well. However, I'll be refactoring and trying the second technique at the end of this week.
I'm not sure this is a full answer but let me give it a quick shot and I can update it when I have a little more time.
Firstly I would start by having the job perhaps as part of the to address. Use comment+1#domain.com with 1 signifying that this is job number one. This part after the plus is called the is the disposable part in CloudMailin (params[:disposable]. The users email address can then be taken from the message body either using params[:from] or Mail.new(params[:message]).from (sometimes the from address given to the SMTP server is different to the one in the header)
Next you have the comment itself which can simply be the plain param.
This gives something like the following:
def create
#job = Job.find(params[:disposable])
if comment = #job.comments.create(:text => params[:plain], :commenter => User.find_by_email(params[:from])
render :text => 'Success', :status => 401
else
render :text => comment.errors.inspect, :status => 422, :content_type => 'text/plain'
end
I hope that helps. It's a bit rough but hopefully it gives the right idea.

Resources