I'm pretty sure there is a better way to do what I want to do, so please tell me.
I have an Item model that can either be sold to someone (have a sale_price and a buyer_id) or be passed (not sold to anyone - sale_price of zero and no buyer_id).
Until now I just relied on the user entering the appropriate price/buyer combination, but I'd like to add a second submit button to the Item edit form that just says 'pass'. (<input type="submit" name="pass" value="Pass" />).
Upon submission by pressing that button, I'd like to override whatever sale_price and buyer_id has been selected by the user and set them myself.
I assume I should do a :before_save in item.rb, but I don't know how to detect the button from the model - or if it's even possible (or advised).
Thanks
You can differentiate the commit type in your controller:
def create
item = Item.new(params[:item])
if params[:commit] == "Pass"
item.sale_price = nil
item.buyer_id = nil
end
if item.save
# ...usual rails stuff
end
end
Of course, if you have the commit type in the controller, you can pass it into the model with a virtual attribute and use callbacks if you like:
class Item < ActiveRecord:Model
attr_accessor :pass
before_save :reset_sale_price
private
def reset_sale_price
if pass
self.sale_price = nil
self.buyer_id = nil
end
end
end
class ItemsController < ApplicationController
def create
item = Item.new(params[:item])
item.pass = (params[:commit] == "Pass")
if item.save
#... standard rails stuff
end
end
end
Hope it helps. Cheers!
Related
I have information in my rails view that I only want to show up if the user has entered all personal details in the database, such as name, firstname, street and city. I could now do this:
if user.name && user.firstname && user.street && user.street
# show stuff
end
but I don't think that is very elegant and "the rails way". Is there an easier and smarter way to do this?
You can use required in your html form tags and validations in Model Class. Also follow links:
http://guides.rubyonrails.org/active_record_validations.html
http://www.w3schools.com/tags/att_input_required.asp
In your model
class User < ActiveRecord::Base
def has_required_fields?
self.name && self.first_name && self.address && ....
end
end
And in your controller
if user.has_required_fields?
# do whatever you want
end
The "rails way" would be thin controller, fat model. So, in your case, you'd want to create a method inside your User model and use it in your controller afterwards.
User model:
def incomplete?
name.blank? or firstname.blank? or street.blank?
end
User controller:
unless user.incomplete?
# Show stuff
end
in model:
ALL_REQUIRED_FIELDS = %w(name surname address email)
def filled_required_fields?
ALL_REQUIRED_FIELDS.all? { |field| self.attribute_present? field }
end
in your controller:
#user.filled_required_fields?
will return true if all fields filled and false if not.
looks very gracefully :)
This is more going into rails theory. I want to compare strings submitted by a user to strings in a populated model. Is this possible? Even if it is possible would it be better to create a user in putted model and compare the strings from there?
Is there any documentation on how to achieve this
My names are kind of wonky, I adapted this from a microposts tutorial to try and be a dna(user input) --> rna (mrna db) sequencer (which i understand is very bad form)
users/new.html.erb(renders)/_form.hrml.erb
<%= form_for :user do |t| %>
<%= t.fields_for 'inputdna[]', [] do |p| %>
dna <%= p.text_field :dna %>
<% end %>
<%= t.submit "Submit" %>
<% end %>
user model
class User < ActiveRecord::Base
dna_options = 'ttt, ttc, tta'.split(',')
#validates :dna_options, presence: true
# returns true|false
def dna_valid?(user_input)
user.input.each
return false if unless dna_options.include? user_input
end
return true
end
controllers/users_controller.rb
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.new # not touched, however the convention would normally be User.new
end
def new
User.create(full: params['user']['full'], dna: params['user']['inputdna']['dna'], mrna: params['user']['mrna']) if User.dna_valid? params['user']['inputdna']['dna']
end
end
seed.rb for users model
User.create(full: "phenylalanine", dna: "ttt", mrna: "uuu")
User.create(full: "phenylalanine", dna: "ttc", mrna: 'uuc')
User.create(full: "leucine", dna: 'tta', mrna: 'uua')
It is possible to compare strings, there are few methods to do so, and the difficulty around user inputs that may prove a challenge.
Assuming you had a model such as:
Class SomeStrings
##some_string = 'String Answer'
end
You could compare this to user input from some params like so:
params['user_input'] == SomeStrings.some_string
This will return a boolean (true|false) for use in if/case statements.
Now, to ensure that the inputs match regardless of case you have two simple options:
params['user_input'].downcase == SomeStrings.some_string.downcase
or
params['user_input'].casecmp(SomeStrings.some_string)
http://ruby-doc.org/core-1.9.3/String.html#method-i-casecmp
The latter approach with casecmp is alot faster than downcasing both string parts.
Now in this example I used a class variable ##some_string, however you could apply the same logic to any model with variables/methods that return a string. This model could be an activerecord, or other ORM record, or just a class.
Shout if you want anymore input.
<>
If you wish to pre-populate this model with something on a user by user basis you will need create some level of persistence. This could be in your code 'hard coded', a database or the session. For example, if you want to compare some users input against one of a list of 5 words stored in the session you could do this:
session['words_to_compare_to'] = Words.generate_five_random_words unless session['words_to_compare_to']
you could create a method on your model that creates words, and this would assign them into the session. This means each user would get some words to compare to which are random per user. This could be your method:
class Words
##words_list = 'help, go, north, fred, mimi, the, and, elf'.split(",")
def generate_five_random_words
words_to_return = []
5.times{ words_to_return << ##words_list.sample }
return words_to_return
end
end
Then to compare the input you receive to see if it is within the 5 random words in your controller you could do this:
session['words_to_compare_to'].include? params['user_input'].downcase
We are using downcase here as all of our words list are lower case. This returns a boolean true|false if the user input is found within the array of 5 words. I hope this provides something that you can reuse.
* Update following code addition to question *
I am going to assume that the user fills out the text field and submits it to a route /user/create. I am assuming the purpose is to check that the 3 letter dna that the user submitted is within an acceptable dna list.
So to start, lets add the acceptable dna combinations to the user model:
Class User
dna_options = 'ttt, ttc, tta'.split(',')
# returns true|false
def self.dna_valid?(user_input)
dna_options.include? user_input
end
end
Now, depending on which ORM you are using, you can also use validators for this: http://guides.rubyonrails.org/active_record_validations.html
To use the above within your controller you could do this:
class UsersController < ApplicationController
def index
#users = Array.new # not touched, however the convention would normally be User.new
end
def create
User.create(full: params['user']['full'], dna: params['user']['inputdna']['dna'], mrna: params['user']['mrna']) if User.dna_valid? params['user']['inputdna']['dna']
end
end
Now, I have made lots of assumptions here, as your code is missing the same entities as your model, however I hope you see what can be done. If params['user']['inputdna'] returns an array, you could change the code to:
if user.dna_valid? params['user']['inputdna']
and change the boolean operator within the model to:
# returns true|false
# expects user_input to be an array
def self.dna_valid?(user_input)
user.input.each do |dna|
return false if unless dna_options.include? dna
end
return true
end
This returns true if all the entities are found within the dna_options, or false if one of them does not
If you're looking for only comparing and finding exact matches, then this is what I used.
all_users = params[:user][:dna].map do |u|
User.find_by(name: u)
end
Here you're getting the response from the form submission in the "params[:user]", then it is comparing that response to the User table using the "User.find_by(name: u)" and assigning matches to "all_users" through the map loop.
The problem you might encounter here is if the form submission does not find an entry in the model, which will then return a "nil". This simple logic does not deal with "nil" returns.
I'm trying to save in Note which Employee was the last editor of a `Note'
In a View, I'm able to access the current employee like this:
<h4><%= current_user.employee.id%></h4>
But, in a Model, I can't use current_user.employee.id.
So, I'm trying this in the User model:
def self.current
Thread.current[:user]
end
def self.current=(user)
Thread.current[:user] = user
end
And this in the Note model:
before_create :record_update
before_update :record_update
protected
def record_update
self.lasteditor_id = User.current.employee.id unless User.current.employee.id.nil?
end
What I'm getting is the last User in the Users table.
Thanks for the help!
current_user gets the logged in user information from the session. You cannot access session variables from model. If you want to update the Note model with the Last employee who viewed it, do it in your controller(most likely show action of your note or any other action you think would be right)
def show
#note = Note.find(params[:id])
#note.update_atribute(:last_viewed_by, current_user.id)
end
You code might look different from above. But this is the idea
I am trying to create persistante variable local to my model but although something that sounds so simple is not working.
I have this in my model:
class Coupon < ActiveRecord::Base
#username = "empty"
#admin = false
def self.setUser(name, isAdmin)
#username = name
#admin = isAdmin
end
def self.get_user (user)#an attempt to access the current_user but did not work i call this from the controller (I understand it is not best practice)
##user = user
self.setUser(user.username,user.admin?)
end
def has_not_occurred
errors.add("property_of","name is not valid:#{#username}") if !validPropertyOf?
end
end
def validProperty_of?
return property_of == #username # || #Admin
end
end
I actually get a "" instead of "empty" or the new value of username in set.user. How do I make these values persist? I have printed the values inside each method so they persist inside the method but not beyond for some reason.
#username is always nil or "" when it gets to has_not_accurred.
Why is this and how do I make it persist? Thank you so much.
I cannont access #user when I set it either (get_user method). I get a nil instance later down at validateProperty_of
I think you forget about database table, you haven't create this one, that's why every variables are non-persistent.
Upgraded Rails now it works. Not sure why.
I have a model named Post and I created two methods within the model that make changes to fields. The first method's changes get persisted when a save is called. The second method's changes do not get saved. I have noticed this behavior before in other models and I think I'm missing some basic knowledge on how models work. Any help on this would be greatly appreciated!
class Post < ActiveRecord::Base
def publish(user) # These changes get saved
reviewed_by = user
touch(:reviewed_at)
active = true
end
def unpublish() # These changes get ignored.
reviewed_by = nil
reviewed_at = nil
active = false
end
end
EDIT:
Here is a snippet from the controller"
class PostsController < ApplicationController
def publish
if request.post?
post = Post.find(params[:id].to_i)
post.publish(current_user)
redirect_to(post, :notice => 'Post was successfully published.')
end
end
def unpublish
if request.post?
post = Post.find(params[:id].to_i)
post.unpublish()
redirect_to(post, :notice => 'Post was successfully unpublished.')
end
end
...
UPDATE
Problem was solved by adding self to all the attributes being changed in the model. Thanks Simone Carletti
In publish you call the method touch that saves the changes to the database. In unpublish, you don't save anything to the database.
If you want to update a model, be sure to use a method that saves the changes to the database.
def publish(user)
self.reviewed_by = user
self.active = true
self.reviewed_at = Time.now
save!
end
def unpublish
self.reviewed_by = nil
self.reviewed_at = nil
self.active = false
save!
end
Also, make sure to use self.attribute when you set a value, otherwise the attribute will be consideres as a local variable.
In my experience you don't persist your changes until you save them so you can
explicitly call Model.save in your controller
explicitly call Model.update_attributes(params[:model_attr]) in your controller
if you want to save an attribute in your model I saw something like write_attribute :attr_name, value but TBH I never used it.
Cheers