Rails: difference between attr_accessor and attr_accessible - ruby-on-rails

What is the difference? Also, why does this not work:
The variables such as base_path are not being set.
class Cvit < ActiveRecord::Base
attr_accessible :species,:program,:textup,:e_value,:filter,:min_identity,:cluster_dist,:fileup_file_name
attr_accessor :base_path, :fa_file, :text_file, :dbase, :source, :bl_file, :bl_sorted, :gff_file, :cvt_file, :db, :overlay_coords_gray
def initilize(*args)
super(*args)
end
def cvitSetup()
self.base_path = "blast_cvit/"
self.fa_file = "input.fa"
.
.
end
end
in the rails console the attributes get set correctly however when I try to do this:
controller:
def show
#cvit = Cvit.find(params[:id])
#cvit.cvitSetup()
#cvit.blast()
#cvit.generateGff()
#cvit.generateCvitImage()
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #cvit }
end
end
and in my view I reference #cvit.some_attribute.html_safe but that attribute is null so I get an error. Any ideas?

attr_accessor creates the getter method.attribute and setter method.attribute= for the specified attributes.
attr_accessible is from ActiveRecord::Base and "Specifies a white list of model attributes that can be set via mass-assignment." See documentation and example here.
EDIT:
As for your second question, I don't know. I tried this dummy code and it worked:
class Test
attr_accessor :base_path, :fa_file
def cvitSetup()
self.base_path = "blast_cvit/"
self.fa_file = "input.fa"
end
end
t = Test.new
t.cvitSetup
p t.base_path
#=> "blast_cvit/"
Are you sure that you properly instantiated your class?

attr_accessor simply creates a getter-setter method for an attribute.
attr_accessible specifies a white list of model attributes that can be set via mass-assignment, such as new(attributes), update_attributes(attributes), or attributes=(attributes). This has been excerpted from the link here

Related

How to associate a form object?

I'm trying to save a Form Object in Rails through and association like this:
document.translations_forms.save(translation_params)
And on my Document model I associated it this way:
class Document < ApplicationRecord
has_many :translations_forms
...
end
But when I run the first command above, I getting this error:
NoMethodError: undefined method `relation_delegate_class' for Document::TranslationsForm:Class
I tried declaring the TranslationFrom Object adding the Document namespace
class Document::TranslationsForm
include ActiveModel::Model
belongs_to :document
def save(params: {})
return false if invalid?
self.document.translation.create(params)
end
end
But didn't work either, my TranslationForm object is in the app/forms/translations_form.rb directory, and I'm using rails 6, what can I do to associate the model with my form object?
A form object (which is a vague term) is usually just a variation of the Decorator pattern.
So you could simply setup the form object so that it wraps an instance of the model class:
class Document
class TranslationForm
include ActiveModel::Model
attribute_reader :document
def initialize(record = nil, attributes = {})
# lets you use the form object for existing records
if record
#document = record
#document.assign_attributes(attributes)
end
#document ||= Document.new(attributes)
end
def to_model
document
end
def save
# triggers validations on the form object
if valid?
document.save
else
false
end
end
end
end
def create
#document = Document::TranslationForm.new(document_params)
if #document.save
redirect_to #document
else
render :new
end
end
def update
#document = Document::TranslationForm.new(
Document.find(params[:id]),
document_params
)
if #document.save
redirect_to #document
else
render :edit
end
end
To add a validation to the form object (instead of directly to the model) just use delegatation:
class Document
class TranslationForm
# ...
validates :foo, presence: true
delegate :errors, to: :document
delegate :foo, to: :document
end
end
delegate :errors, to: :document makes it so that your validations will add errors to the underlying model instead of the errors object of your form object.

ActiveRecord::RecordNotFound - in a descendant class' associated_controller#index

I am attempting to locate a parent object in a nested controller, so that I can associate the descendant resource with the parent like so:
# teams_controller.rb <snippet only>
def index
#university = Univeresity.find(params[:university_id])
#teams = #university.teams
end
When I call find(params[:university_id]) per the snippet above & in line 6 of teams_controller.rb, I receive ActiveRecord::RecordNotFound - Couldn't find University without an ID.
I'm not only interested in fixing this issue, but would also enjoy a better understanding of finding objects without having to enter a University.find(1) value, since I grant Admin the privilege of adding universities.
The Rails Guides say the following about the two kinds of parameters in a website:
3 Parameters
You will probably want to access data sent in by the user or other
parameters in your controller actions. There are two kinds of
parameters possible in a web application. The first are parameters
that are sent as part of the URL, called query string parameters. The
query string is everything after “?” in the URL. The second type of
parameter is usually referred to as POST data. This information
usually comes from an HTML form which has been filled in by the user.
It’s called POST data because it can only be sent as part of an HTTP
POST request. Rails does not make any distinction between query string
parameters and POST parameters, and both are available in the params
hash in your controller:
It continues a little further down, explaining that the params hash is an instance of HashWithIndifferentAccess, which allows usage of both symbols and strings interchangeably for the keys.
From what I read above, my understanding is that Rails recognizes both parameters (URL & POST) and stores them in the same hash (params).
Can I pass the params hash into a find method in any controller action, or just the create/update actions? I'd also be interested in finding a readable/viewable resource to understand the update_attributes method thats called in a controller's 'update' action.
Please overlook the commented out code, as I am actively searching for answers as well.
Thanks in advance.
Here are the associated files and server log.
Webrick
teams_controller.rb
class TeamsController < ApplicationController
# before_filter :get_university
# before_filter :get_team
def index
#university = University.find(params[:univeristy_id])
#teams = #university.teams
end
def new
#university = University.find(params[:university_id])
#team = #university.teams.build
end
def create
#university = University.find(params[:university_id])
#team = #university.teams.build(params[:team])
if #team.save
redirect_to [#university, #team], success: 'Team created!'
else
render :new, error: 'There was an error processing your team'
end
end
def show
#university = University.find(params[:university_id])
#team = #university.teams.find(params[:id])
end
def edit
#university = University.find(params[:university_id])
#team = #university.teams.find(params[:id])
end
def update
#university = University.find(params[:university_id])
#team = #university.teams.find(params[:id])
if #team.update_attributes(params[:team])
redirect_to([#university, #team], success: 'Team successfully updated')
else
render(:edit, error: 'There was an error updating your team')
end
end
def destroy
#university = University.find(params[:university_id])
#team = #university.teams.find(params[:id])
#team.destroy
redirect_to university_teams_path(#university)
end
private
def get_university
#university = University.find(params[:university_id]) # can't find object without id
end
def get_team
#team = #university.teams.find(params[:id])
end
end
team.rb
class Team < ActiveRecord::Base
attr_accessible :name, :sport_type, :university_id
has_many :home_events, foreign_key: :home_team_id, class_name: 'Event'
has_many :away_events, foreign_key: :away_team_id, class_name: 'Event'
has_many :medias, as: :mediable
belongs_to :university
validates_presence_of :name, :sport_type
# scope :by_university, ->(university_id) { where(team_id: team_id).order(name: name) }
# scope :find_team, -> { Team.find_by id: id }
# scope :by_sport_type, ->(sport_type) { Team.where(sport_type: sport_type) }
# scope :with_university, joins: :teams
# def self.by_university(university_id)
# University.where(id: 1)
# University.joins(:teams).where(teams: { name: name })
# end
def self.by_university
University.where(university_id: university_id).first
end
def self.university_join
University.joins(:teams)
end
def self.by_sport_type(sport_type)
where(sport_type: sport_type)
end
def self.baseball
by_sport_type('Baseball/Softball')
end
end
university.rb
class University < ActiveRecord::Base
attr_accessible :address, :city, :name, :state, :url, :zip
has_many :teams, dependent: :destroy
validates :zip, presence: true, format: { with: /\A\d{5}(-\d+)?\z/ },
length: { minimum: 5 }
validates_presence_of :name, :address, :city, :state, :url
scope :universities, -> { University.order(name: 'ASC') }
# scope :by_teams, ->(university_id) { Team.find_by_university_id(university_id) }
# scope :team_by_university, ->(team_id) { where(team_id: team_id).order(name: name)}
def sport_type
team.sport_type
end
end
views/teams/index.html.erb
Placed in gists for formatting reasons
rake routes output: (in a public gist)
enter link description here
rails console
You're not going to want to have both:
resources :universities #lose this one
resources :universities do
resources :teams
end
As for params... you have to give a param. So, when you go to http://localhost:3000/teams there are no params, by default. If you go to http://localhost:3000/teams/3 then params[:id] = 3 and this will pull up your third team.
Keep in mind the nomenclature of an index. The index action of Teams, is going to list all of the teams. All of them. There is no one University there, so what are you actually trying to find? If anything, you'd have, for your University controller:
def show
#university = University.find(params[:id])
#teams = #university.teams
end
so, the address bar will be showing http://localhost:3000/universities/23, right? params[:id] = 23, then you can find the teams associated with that university.

Passing instance variables into API in rails

I'm trying to pass in some instance variables to call an API with that specific object's attributes. A user fills in their car details (make, model, and year) which creates an offer object. That is supposed to be passed into Edmund's API to retrieve the info for that car. The code works fine if I set it with a specific make/model/year but I can't make it return info for a created offer object.
Here's my controller:
def show
#offer = Offer.find(params[:id])
#wanted_ad = WantedAd.find(params[:wanted_ad_id])
#make = #offer.ownermake
#model = #offer.ownermodel
#year = #offer.owneryear
respond_to do |format|
format.html # show.html.erb
format.json { render json: #offer }
end
end
And here's my model:
class Offer < ActiveRecord::Base
attr_accessible :user_id, :wanted_ad_id, :estvalue, :image1, :offerprice, :ownercartype, :ownerdesc, :ownermake, :ownermileage, :ownermodel, :owneryear
belongs_to :user
belongs_to :wanted_ad
has_one :car
def self.carsearch
#car = []
carinfo = HTTParty.get("http://api.edmunds.com/v1/api/vehicle/#{make}/#{model}/#{year}?api_key=qd4n48eua7r2e59hbdte5xd6&fmt=json")
carinfo["modelYearHolder"].each do |p|
c = Car.new
c.make = p["makeName"]
return carinfo
end
end
end
My car model is simply:
class Car < ActiveRecord::Base
attr_accessible :make, :model, :year
belongs_to :offer
end
And I'm trying to call it from a view file with <%= Offer.carsearch %>. I'm probably all sorts of messed up but this is my first time working with an API and I'm very lost.
I think you got several logical errors in your carsearch method:
You're fetching a carinfo, iterate through an array, instantiate a new car but nothing happens with the c object and at the end of the first iteration you exit the whole function returning the retrieved carinfo...
Is this probably what you've meant?
def carsearch
#cars = []
# where do `make`, `model` and `year` come from here?
# probably method parameters!?
carinfo = HTTParty.get("http://api.edmunds.com/v1/api/vehicle/#{make}/#{model}/#{year}?api_key=qd4n48eua7r2e59hbdte5xd6&fmt=json")
carinfo["modelYearHolder"].each do |p|
c = Car.new
c.make = p["makeName"]
# initialize other attributes (year, model)?
#cars << c
end
return #cars
end

Ruby on Rails Controller action is a private method

I am getting
private method `new' called for Reminder:Class
The Application trace is
app/controllers/reminders_controller.rb:27:in `new'
The new action is as follows
def new
#reminder = #current_user.reminders.build()
#title = "New Reminder"
respond_to do |format|
format.html # new.html.erb
format.json { render json: #reminder }
end
end
The Reminder Model is has follows
class Reminder < ActiveRecord::Base
belongs_to :user
belongs_to :assignment
attr_accessible :datetime, :sent_at, :status, :send_time
STATUSES = ["Not Sent", "Sending", "Sent", "Canceled"]
validates_presence_of :sent_at, :status, :user_id, :assignment_id
before_save :round_tine
def round_time
self.send_time = Time.at(t.to_i/(15*60)*(15*60))
end
end
I don't know how the method would be private. Thanks for the help in advance!
UPDATE: Added a method to the model. Error still occurs.
put mailer class name as ReminderMailer not just Reminder. That's the problem rails is not able to distinguish between two classes and it is identifying the new method for mailer class which has name Reminder and showing the error.
You probably have the private declaration somewhere above your new definition. Post the entirety of your reminders_controller or just remove that offending line.

Rails: return model (not bound to active record) as xml

I have a model class that is not bound to Active record.
class ProcessingStatus
attr_accessor :status, :timestamp
end
The model acts as a processing status holder and will eventually be returned to the calling method.
Since this is invoked as an active resource method, this needs to go back (serialized) as xml.
Here is my action method:
def activate
#process_status = ProcessingStatus.new
if Account.activate(params[:account])
#process_status.status = "success"
else
#process_status.status = "fail"
end
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #process_status }
end
end
This doesn't seem to return a valid xml though.
If I try and output the #process_status like below
return render :text => "The object is #{#process_status}"
this is what I get:
The object is #<ProcessingStatus:0x00000005e98860>
Please tell me what I am missing.
Edit #1,
Based on the comment below, I modified my code to include the serialization libraries.
class ProcessingStatus
include ActiveModel::Serialization
include ActiveModel::Serializers::JSON
include ActiveModel::Serializers::Xml
attr_accessor :status
def attributes
#attributes ||= {'status' => 'nil'}
end
end
I am getting closer:) Now get the output as follows for .xml request.
but the value that I assigned is not reflected.
#process_status.status = "success" / "fail"
<processing-status><status>nil</status></processing-status>
but when i make a json request, it is appearing correct!
{"processing_status":{"status":"success"}}
You need to define method to_xml in your model, or include Serialization module as below:
class ProcessingStatus
include ActiveModel::Serialization
attr_accessor :status, :timestamp
end
Here you've got more info: http://api.rubyonrails.org/classes/ActiveModel/Serialization.html

Resources