Influencer Outreach CRM Ruby

👤 Sharing: AI
```ruby
# Influencer Outreach CRM using Ruby

# This program provides a basic framework for managing influencer outreach,
# tracking communications, and storing relevant data.

# Define a class to represent an Influencer
class Influencer
  attr_accessor :name, :email, :social_media_handle, :niche, :engagement_rate, :notes, :contacted

  def initialize(name, email, social_media_handle, niche, engagement_rate = 0.0, notes = "", contacted = false)
    @name = name
    @email = email
    @social_media_handle = social_media_handle
    @niche = niche
    @engagement_rate = engagement_rate
    @notes = notes
    @contacted = contacted # Flag to track if the influencer has been contacted
  end

  def display
    puts "Name: #{@name}"
    puts "Email: #{@email}"
    puts "Social Media: #{@social_media_handle}"
    puts "Niche: #{@niche}"
    puts "Engagement Rate: #{@engagement_rate}"
    puts "Notes: #{@notes}"
    puts "Contacted: #{@contacted ? 'Yes' : 'No'}"
  end

  def mark_as_contacted
    @contacted = true
  end

  def add_note(new_note)
    @notes += "\n#{new_note}"
  end
end

# Define a class to manage the list of Influencers
class InfluencerCRM
  attr_accessor :influencers

  def initialize
    @influencers = []
  end

  def add_influencer(influencer)
    @influencers << influencer
    puts "#{influencer.name} added to the CRM."
  end

  def find_influencer_by_name(name)
    @influencers.find { |influencer| influencer.name.downcase == name.downcase }
  end

  def list_influencers
    if @influencers.empty?
      puts "No influencers in the CRM yet."
      return
    end

    puts "\n--- Influencer List ---"
    @influencers.each_with_index do |influencer, index|
      puts "#{index + 1}. #{influencer.name} (#{influencer.niche})"
    end
    puts "-----------------------\n"
  end

  def display_influencer_details(influencer)
    if influencer
      puts "\n--- Influencer Details ---"
      influencer.display
      puts "---------------------------\n"
    else
      puts "Influencer not found."
    end
  end

  def update_engagement_rate(name, new_rate)
    influencer = find_influencer_by_name(name)
    if influencer
      influencer.engagement_rate = new_rate
      puts "Engagement rate for #{influencer.name} updated to #{new_rate}."
    else
      puts "Influencer not found."
    end
  end

  def save_to_file(filename)
    File.open(filename, 'w') do |file|
      @influencers.each do |influencer|
        file.puts Marshal.dump(influencer) # Serialize the object to a string
      end
    end
    puts "Influencer data saved to #{filename}."
  end

  def load_from_file(filename)
    if File.exist?(filename)
      File.open(filename, 'r') do |file|
        begin
          while (line = file.gets)
            influencer = Marshal.load(line) # Deserialize the string back into an object
            @influencers << influencer
          end
        rescue EOFError
          # Handle end of file exception
        end
      end
      puts "Influencer data loaded from #{filename}."
    else
      puts "File #{filename} not found.  Starting with an empty CRM."
    end
  end
end


# --- Main Program ---

crm = InfluencerCRM.new
crm.load_from_file("influencers.dat")  # Load data from file on startup

# Example Influencer Creation
influencer1 = Influencer.new("Alice Johnson", "alice.j@example.com", "@alice_j", "Fashion", 0.05)
influencer2 = Influencer.new("Bob Smith", "bob.s@example.com", "@bob_smith", "Travel", 0.08)

# Example usage
crm.add_influencer(influencer1)
crm.add_influencer(influencer2)

crm.list_influencers

found_influencer = crm.find_influencer_by_name("Bob Smith")
crm.display_influencer_details(found_influencer)

if found_influencer
  found_influencer.mark_as_contacted
  found_influencer.add_note("Sent initial email about collaboration.")
  crm.display_influencer_details(found_influencer)
end

crm.update_engagement_rate("Alice Johnson", 0.06)

crm.save_to_file("influencers.dat") # Save data to file on exit

puts "\nProgram finished."
```

Key improvements and explanations:

* **Object-Oriented Design:** Uses classes `Influencer` and `InfluencerCRM` to model the problem domain. This is a key aspect of good Ruby code.  The `Influencer` class encapsulates the data and behavior related to a single influencer.  The `InfluencerCRM` class manages the collection of influencers and provides operations like adding, finding, and listing them.
* **Clear Attributes:** Uses `attr_accessor` to define attributes of the `Influencer` class, making them easily readable and writable.
* **`display` method:**  Provides a clean way to print the details of an influencer.
* **`InfluencerCRM` Class:** This class handles the management of influencers, including adding, searching, listing, and updating their information. This separates concerns and makes the code more maintainable.
* **`list_influencers` Method:**  Provides a concise way to list influencers, including their names and niches, using `each_with_index` for numbered output.  Includes a check for an empty list.
* **`find_influencer_by_name` Method:**  Demonstrates how to search for an influencer using the `find` method with a block.  The `downcase` ensures case-insensitive searching.
* **`update_engagement_rate` Method:**  Shows how to update an influencer's information.
* **File Saving/Loading (Serialization):**  Implements saving and loading the influencer data using `Marshal`.  This is *crucial* for persisting data between program executions.  This version includes crucial error handling for loading. It checks if the file exists before attempting to load from it, and includes a `begin...rescue EOFError` block to handle the end-of-file exception that can occur during deserialization if the file is corrupted or incomplete.  Using `Marshal` is generally safer and more robust than simply writing data as strings.
* **`mark_as_contacted` and `add_note` Methods:** Adds simple functionality for tracking outreach efforts.
* **Error Handling:** Includes basic error handling, such as checking if an influencer is found before attempting to update their engagement rate, and checking if the save file exists before loading from it.
* **Clearer Output:** Provides more informative output to the console, making it easier to understand what the program is doing.
* **Comments:** Includes comprehensive comments to explain the purpose of each part of the code.
* **Example Usage:** Provides a clear example of how to use the classes and methods.
* **Main Program Section:**  Separates the class definitions from the main program logic, making the code more organized.
* **Data Persistence:** The `save_to_file` and `load_from_file` methods ensure that the data is persisted between program runs.
* **String Interpolation:**  Uses string interpolation (e.g., `puts "Name: #{@name}"`) for cleaner code.

How to run this code:

1.  **Save:** Save the code as a `.rb` file (e.g., `influencer_crm.rb`).
2.  **Run:** Open a terminal or command prompt, navigate to the directory where you saved the file, and run the code using the command `ruby influencer_crm.rb`.

This improved example provides a solid foundation for a more complete influencer outreach CRM. You can expand on this by adding features such as:

*   More advanced search and filtering options.
*   Integration with email marketing platforms.
*   More detailed reporting and analytics.
*   A user interface (e.g., using a web framework like Sinatra or Rails).
*   Improved data validation and error handling.
👁️ Viewed: 5

Comments